VYPR
Unrated severityNVD Advisory· Published Jun 3, 2026

CVE-2026-9334

CVE-2026-9334

Description

Cpanel::JSON::XS before 4.41 allows type confusion via duplicate JSON keys when dupkeys_as_arrayref is enabled, leading to crashes.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Cpanel::JSON::XS before 4.41 allows type confusion via duplicate JSON keys when dupkeys_as_arrayref is enabled, leading to crashes.

Vulnerability

Cpanel::JSON::XS versions prior to 4.41 for Perl are vulnerable to a type confusion flaw when parsing JSON with duplicate object keys and the dupkeys_as_arrayref option enabled. The decode_hv() function incorrectly dereferences a scalar as a reference when a duplicate key is encountered, leading to a crash [1, 2]. This affects versions before 4.41.

Exploitation

An attacker can exploit this vulnerability by providing a specially crafted JSON string containing duplicate keys to an application that uses Cpanel::JSON::XS with the dupkeys_as_arrayref option set to true. The attacker needs to be able to control the JSON input being decoded. A successful exploitation involves sending JSON like {"a":1,"a":2,"b":3,"b":4} which triggers the type confusion [2].

Impact

Successful exploitation of this vulnerability can lead to a denial-of-service condition by crashing the application. The type confusion occurs when the code attempts to dereference a scalar value as a reference, potentially leading to a segmentation fault. The attacker-controlled scalar contents are used in the pointer dereference, indicating a potential for more severe memory corruption, though the available references primarily describe a crash [2].

Mitigation

This vulnerability is fixed in Cpanel::JSON::XS version 4.41, released on 2026-05-27 [1]. Users are advised to upgrade to version 4.41 or later. No workarounds are described in the available references.

AI Insight generated on Jun 3, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

2
11a7c550a0d8

dupkeys_as_arrayref type confusion (CVE-2026-9334)

https://github.com/rurban/Cpanel-JSON-XSPaul JohnsonMay 25, 2026via nvd-ref
2 files changed · +63 34
  • t/26_duplicate.t+31 1 modified
    @@ -1,5 +1,5 @@
     use strict;
    -use Test::More tests => 12;
    +use Test::More tests => 17;
     use Cpanel::JSON::XS;
     
     my $json = Cpanel::JSON::XS->new;
    @@ -47,3 +47,33 @@ is (encode_json ($json->decode ('{"a":["b"],"a":"c"}')), '{"a":[["b"],"c"]}',
         'dupkeys_as_arrayref to []');
     is (encode_json ($json->decode ('{"a":["b","c"],"a":["c"]}')), '{"a":[["b","c"],["c"]]}',
         'dupkeys_as_arrayref to [[]]');
    +
    +# fast path: short ASCII keys
    +is_deeply ($json->decode ('{"a":1,"a":2,"b":3,"b":4}'),
    +           { a => [1, 2], b => [3, 4] },
    +           'dupkeys_as_arrayref: two distinct duplicated keys, fast path');
    +
    +# slow path: keys longer than 24 bytes force _decode_str
    +{
    +  my $k1 = 'a' x 30;
    +  my $k2 = 'b' x 30;
    +  my $in = qq({"$k1":1,"$k1":2,"$k2":3,"$k2":4});
    +  is_deeply ($json->decode ($in),
    +             { $k1 => [1, 2], $k2 => [3, 4] },
    +             'dupkeys_as_arrayref: two distinct duplicated keys, slow path');
    +}
    +
    +# three distinct duplicated keys - confirms fix past the first transition
    +is_deeply ($json->decode ('{"a":1,"a":2,"b":3,"b":4,"c":5,"c":6}'),
    +           { a => [1, 2], b => [3, 4], c => [5, 6] },
    +           'dupkeys_as_arrayref: three distinct duplicated keys');
    +
    +# triple duplicate of a second key - further dups should append, not re-wrap
    +is_deeply ($json->decode ('{"a":1,"a":2,"b":3,"b":4,"b":5}'),
    +           { a => [1, 2], b => [3, 4, 5] },
    +           'dupkeys_as_arrayref: triple dup of second key');
    +
    +# pre-existing arrayref values combine correctly across multiple keys
    +is_deeply ($json->decode ('{"a":["x"],"a":"y","b":["p"],"b":"q"}'),
    +           { a => [['x'], 'y'], b => [['p'], 'q'] },
    +           'dupkeys_as_arrayref: existing array values, two distinct keys');
    
  • XS.xs+32 33 modified
    @@ -366,7 +366,6 @@ mingw_modfl(long double x, long double *ip)
     #define F_REQUIRE_TYPES   0x01000000UL
     #define F_TYPE_ALL_STRING 0x02000000UL
     #define F_DUPKEYS_AS_AREF 0x04000000UL
    -#define F_DUPKEYS_FIRST   0x08000000UL /* internal only */
     #define F_HOOK            0x80000000UL /* some hooks exist, so slow-path processing */
     
     #define F_PRETTY    F_INDENT | F_SPACE_BEFORE | F_SPACE_AFTER
    @@ -3924,7 +3923,7 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
       int allow_barekey = dec->json.flags & F_ALLOW_BAREKEY;
       int allow_dupkeys = dec->json.flags & F_ALLOW_DUPKEYS;
       int dupkeys_as_arrayref = dec->json.flags & F_DUPKEYS_AS_AREF;
    -  int dupkeys_first = dec->json.flags & F_DUPKEYS_FIRST;
    +  HV *dupkeys_seen = NULL;
       char endstr = '"';
     
       DEC_INC_DEPTH;
    @@ -3996,16 +3995,21 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
                           // extend the value to arrayref or push
                           old_value = HeVAL(hv_fetch_ent (hv, keysv, 0, 0));
                           SvREFCNT_inc (old_value);
    -                      if (dupkeys_first) {
    -                        AV *av = newAV ();
    -                        av_extend (av, 2);
    -                        if (av_store(av, 0, old_value))
    -                          old_value = newRV ((SV*)av);
    -                      } else if (SvTYPE (old_value) != SVt_RV &&
    -                                 SvTYPE (SvRV (old_value)) != SVt_PVAV) {
    -                        // not an AvREF
    -                        ERR ("Invalid dupkeys_as_arrayref hash key");
    -                      }
    +                      if (!dupkeys_seen
    +                          || !hv_exists_ent (dupkeys_seen, keysv, 0))
    +                        {
    +                          AV *av = newAV ();
    +                          av_extend (av, 2);
    +                          if (av_store (av, 0, old_value))
    +                            old_value = newRV ((SV*)av);
    +                          if (!dupkeys_seen)
    +                            {
    +                              dupkeys_seen = newHV ();
    +                              sv_2mortal ((SV *)dupkeys_seen);
    +                            }
    +                          (void)hv_store_ent (dupkeys_seen, keysv,
    +                                              newSV (0), 0);
    +                        }
                         } // else overwrite it below
                       }
                       decode_ws (dec);
    @@ -4029,11 +4033,6 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
                         {
                           av_push ((AV*)SvRV (old_value), value);
                           (void)hv_store_ent (hv, keysv, old_value, 0);
    -                      if (dupkeys_first)
    -                        {
    -                          dupkeys_first = 0;
    -                          dec->json.flags &= ~F_DUPKEYS_FIRST;
    -                        }
                         }
                       else
                         {
    @@ -4067,16 +4066,21 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
                           SV** rv = hv_fetch (hv, key, len, 0);
                           old_value = *rv;
                           SvREFCNT_inc (old_value);
    -                      if (dupkeys_first) {
    -                        AV *av = newAV ();
    -                        av_extend (av, 2);
    -                        if (av_store(av, 0, old_value))
    -                          old_value = newRV ((SV*)av);
    -                      } else if (SvTYPE (old_value) != SVt_RV &&
    -                                 SvTYPE (SvRV (old_value)) != SVt_PVAV) {
    -                        // not an AvREF
    -                        ERR ("Invalid dupkeys_as_arrayref hash key");
    -                      }
    +                      if (!dupkeys_seen
    +                          || !hv_exists (dupkeys_seen, key, len))
    +                        {
    +                          AV *av = newAV ();
    +                          av_extend (av, 2);
    +                          if (av_store (av, 0, old_value))
    +                            old_value = newRV ((SV*)av);
    +                          if (!dupkeys_seen)
    +                            {
    +                              dupkeys_seen = newHV ();
    +                              sv_2mortal ((SV *)dupkeys_seen);
    +                            }
    +                          (void)hv_store (dupkeys_seen, key, len,
    +                                          newSV (0), 0);
    +                        }
                         } // else overwrite it below
                       }
     
    @@ -4101,11 +4105,6 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
                         {
                           av_push ((AV*)SvRV (old_value), value);
                           hv_store_str (aTHX_ hv, key, len, old_value);
    -                      if (dupkeys_first)
    -                        {
    -                          dupkeys_first = 0;
    -                          dec->json.flags &= ~F_DUPKEYS_FIRST;
    -                        }
                         }
                       else
                         {
    @@ -4886,7 +4885,7 @@ void ascii (JSON *self, int enable = 1)
             # Turning on DUPKEYS_AS_AREF also turns on ALLOW_DUPKEYS
             # But turning off DUPKEYS_AS_AREF does not
             if (ix == F_DUPKEYS_AS_AREF && enable != 0)
    -          self->flags |= F_ALLOW_DUPKEYS | F_DUPKEYS_FIRST;
    +          self->flags |= F_ALLOW_DUPKEYS;
             XPUSHs (ST (0));
     
     void get_ascii (JSON *self)
    
f0f4551af12a

Merge 2899bb28de16dfbadf5cfc19f6015cb1a46d2918 into bd714d32207c46afe7146d7bb4d02667fe48767e

https://github.com/Perl/perl5iabynAug 16, 2023via body-scan

Vulnerability mechanics

Root cause

"The decode_hv() function incorrectly dereferences a non-reference scalar as a reference when handling duplicate JSON object keys with dupkeys_as_arrayref enabled."

Attack vector

An attacker can trigger this vulnerability by providing a JSON payload with duplicate keys to a system that has enabled the `dupkeys_as_arrayref` option in Cpanel::JSON::XS. The function `decode_hv()` encounters a type confusion when processing the second instance of a duplicate key. This leads to a crash because `SvRV()` is called on a value that is not a reference, causing an invalid pointer to be dereferenced [ref_id=2].

Affected code

The vulnerability resides within the `decode_hv()` function in the `XS.xs` file of Cpanel::JSON::XS. Specifically, the issue occurs in the code paths handling duplicate keys when the `dupkeys_as_arrayref` flag is set [ref_id=2].

What the fix does

The patch modifies the `decode_hv()` function in `XS.xs` to correctly handle duplicate keys when `dupkeys_as_arrayref` is enabled [patch_id=4552434]. It introduces a `dupkeys_seen` hash to track keys that have already been encountered. The logic is updated to ensure that `SvRV()` is only called on actual references, preventing the dereferencing of non-reference scalars and thus resolving the type confusion [ref_id=2].

Preconditions

  • configThe `dupkeys_as_arrayref` option must be enabled for Cpanel::JSON::XS.
  • inputThe input must be a JSON string containing duplicate object keys.

Generated on Jun 3, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.