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- Range: <4.41
Patches
211a7c550a0d8dupkeys_as_arrayref type confusion (CVE-2026-9334)
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)
f0f4551af12aMerge 2899bb28de16dfbadf5cfc19f6015cb1a46d2918 into bd714d32207c46afe7146d7bb4d02667fe48767e
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
2News mentions
0No linked articles in our index yet.