CVE-2022-46175
Description
JSON5 is an extension to the popular JSON file format that aims to be easier to write and maintain by hand (e.g. for config files). The parse method of the JSON5 library before and including versions 1.0.1 and 2.2.1 does not restrict parsing of keys named __proto__, allowing specially crafted strings to pollute the prototype of the resulting object. This vulnerability pollutes the prototype of the object returned by JSON5.parse and not the global Object prototype, which is the commonly understood definition of Prototype Pollution. However, polluting the prototype of a single object can have significant security impact for an application if the object is later used in trusted operations. This vulnerability could allow an attacker to set arbitrary and unexpected keys on the object returned from JSON5.parse. The actual impact will depend on how applications utilize the returned object and how they filter unwanted keys, but could include denial of service, cross-site scripting, elevation of privilege, and in extreme cases, remote code execution. JSON5.parse should restrict parsing of __proto__ keys when parsing JSON strings to objects. As a point of reference, the JSON.parse method included in JavaScript ignores __proto__ keys. Simply changing JSON5.parse to JSON.parse in the examples above mitigates this vulnerability. This vulnerability is patched in json5 versions 1.0.2, 2.2.2, and later.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
JSON5's parse method does not restrict keys named '__proto__', enabling prototype pollution of returned objects up to version 2.2.1.
## What is the vulnerability? CVE-2022-46175 is a prototype pollution vulnerability in the JSON5 library, affecting versions prior to 1.0.2 and 2.2.2. The parse method fails to restrict parsing of keys named __proto__, allowing specially crafted JSON strings to inject arbitrary properties into the prototype of the returned object. Unlike typical prototype pollution, this does not affect the global Object.prototype, but pollutes the prototype of the object returned by JSON5.parse [1][3].
## How it is exploited? An attacker can supply a JSON5 payload containing a __proto__ key, such as {"__proto__": {"isAdmin": true}}. When parsed by JSON5.parse, the resulting object's prototype is modified, adding unexpected keys. The attack requires the application to later use the parsed object in trusted operations without properly filtering keys [3]. The vulnerability is similar in spirit to other prototype pollution flaws, but limited to per-object pollution [1].
Impact
Depending on how the application uses the parsed object, the impact can include denial of service, cross-site scripting, privilege escalation, and in extreme cases remote code execution [1][3]. For example, if the object is used for authorization checks, an attacker could bypass security controls by injecting properties like isAdmin [3].
Mitigation
The vulnerability is patched in json5 versions 1.0.2 and 2.2.2 and later [1][3]. Users should upgrade to these patched versions. As an immediate workaround, developers can replace JSON5.parse with standard JSON.parse when parsing untrusted input, since native JSON.parse ignores __proto__ keys [1].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
json5npm | >= 2.0.0, < 2.2.2 | 2.2.2 |
json5npm | < 1.0.2 | 1.0.2 |
Affected products
1Patches
262a65408408dfix: add __proto__ to objects and arrays
3 files changed · +49 −7
CHANGELOG.md+10 −0 modified@@ -1,3 +1,12 @@ +### Unreleased [[code][c-unreleased], [diff][d-unreleased]] + +[c-unreleased]: https://github.com/json5/json5/tree/v1 +[d-unreleased]: https://github.com/json5/json5/compare/v1.0.1...v1 + +- Fix: Properties with the name `__proto__` are added to objects and arrays. + ([#199]) + + ### v1.0.1 [[code][c1.0.1], [diff][d1.0.1]] [c1.0.1]: https://github.com/json5/json5/tree/v1.0.1 @@ -272,3 +281,4 @@ parser for the regular JSON format. [#108]: https://github.com/json5/json5/pull/108 [#134]: https://github.com/json5/json5/pull/134 [#154]: https://github.com/json5/json5/issues/154 +[#199]: https://github.com/json5/json5/issues/199
src/parse.js+34 −7 modified@@ -42,12 +42,34 @@ export default function parse (text, reviver) { function internalize (holder, name, reviver) { const value = holder[name] if (value != null && typeof value === 'object') { - for (const key in value) { - const replacement = internalize(value, key, reviver) - if (replacement === undefined) { - delete value[key] - } else { - value[key] = replacement + if (Array.isArray(value)) { + for (let i = 0; i < value.length; i++) { + const key = String(i) + const replacement = internalize(value, key, reviver) + if (replacement === undefined) { + delete value[key] + } else { + Object.defineProperty(value, key, { + value: replacement, + writable: true, + enumerable: true, + configurable: true, + }) + } + } + } else { + for (const key in value) { + const replacement = internalize(value, key, reviver) + if (replacement === undefined) { + delete value[key] + } else { + Object.defineProperty(value, key, { + value: replacement, + writable: true, + enumerable: true, + configurable: true, + }) + } } } } @@ -973,7 +995,12 @@ function push () { if (Array.isArray(parent)) { parent.push(value) } else { - parent[key] = value + Object.defineProperty(parent, key, { + value, + writable: true, + enumerable: true, + configurable: true, + }) } }
test/parse.js+5 −0 modified@@ -33,6 +33,11 @@ describe('JSON5', () => { assert.deepStrictEqual(JSON5.parse('{\\u0061\\u0062:1,\\u0024\\u005F:2,\\u005F\\u0024:3}'), {ab: 1, $_: 2, _$: 3}) }) + it('preserves __proto__ property names', () => { + // eslint-disable-next-line no-proto + assert.strictEqual(JSON5.parse('{"__proto__":1}').__proto__, 1) + }) + it('parses multiple properties', () => { assert.deepStrictEqual(JSON5.parse('{abc:1,def:2}'), {abc: 1, def: 2}) })
7774c1097993fix: add __proto__ to objects and arrays
3 files changed · +45 −7
CHANGELOG.md+4 −0 modified@@ -3,6 +3,9 @@ [c-unreleased]: https://github.com/json5/json5/tree/main [d-unreleased]: https://github.com/json5/json5/compare/v2.2.1...HEAD +- Fix: Properties with the name `__proto__` are added to objects and arrays. + ([#199]) + ### v2.2.1 [[code][c2.2.1], [diff][d2.2.1]] [c2.2.1]: https://github.com/json5/json5/tree/v2.2.1 @@ -360,6 +363,7 @@ parser for the regular JSON format. [#182]: https://github.com/json5/json5/issues/182 [#187]: https://github.com/json5/json5/issues/187 [#196]: https://github.com/json5/json5/issues/196 +[#199]: https://github.com/json5/json5/issues/199 [#208]: https://github.com/json5/json5/issues/208 [#210]: https://github.com/json5/json5/issues/210 [#222]: https://github.com/json5/json5/issues/222
lib/parse.js+34 −7 modified@@ -42,12 +42,34 @@ module.exports = function parse (text, reviver) { function internalize (holder, name, reviver) { const value = holder[name] if (value != null && typeof value === 'object') { - for (const key in value) { - const replacement = internalize(value, key, reviver) - if (replacement === undefined) { - delete value[key] - } else { - value[key] = replacement + if (Array.isArray(value)) { + for (let i = 0; i < value.length; i++) { + const key = String(i) + const replacement = internalize(value, key, reviver) + if (replacement === undefined) { + delete value[key] + } else { + Object.defineProperty(value, key, { + value: replacement, + writable: true, + enumerable: true, + configurable: true, + }) + } + } + } else { + for (const key in value) { + const replacement = internalize(value, key, reviver) + if (replacement === undefined) { + delete value[key] + } else { + Object.defineProperty(value, key, { + value: replacement, + writable: true, + enumerable: true, + configurable: true, + }) + } } } } @@ -973,7 +995,12 @@ function push () { if (Array.isArray(parent)) { parent.push(value) } else { - parent[key] = value + Object.defineProperty(parent, key, { + value, + writable: true, + enumerable: true, + configurable: true, + }) } }
test/parse.js+7 −0 modified@@ -48,6 +48,13 @@ t.test('parse(text)', t => { 'parses escaped property names' ) + t.strictSame( + // eslint-disable-next-line no-proto + JSON5.parse('{"__proto__":1}').__proto__, + 1, + 'preserves __proto__ property names' + ) + t.strictSame( JSON5.parse('{abc:1,def:2}'), {abc: 1, def: 2},
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
11- github.com/advisories/GHSA-9c47-m6qq-7p4hghsaADVISORY
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/3S26TLPLVFAJTUN3VIXFDEBEXDYO22CE/mitrevendor-advisory
- nvd.nist.gov/vuln/detail/CVE-2022-46175ghsaADVISORY
- github.com/json5/json5/commit/62a65408408d40aeea14c7869ed327acead12972ghsaWEB
- github.com/json5/json5/commit/7774c1097993bc3ce9f0ac4b722a32bf7d6871c8ghsaWEB
- github.com/json5/json5/issues/199ghsaWEB
- github.com/json5/json5/issues/295ghsaWEB
- github.com/json5/json5/pull/298ghsaWEB
- github.com/json5/json5/security/advisories/GHSA-9c47-m6qq-7p4hghsaWEB
- lists.debian.org/debian-lts-announce/2023/11/msg00021.htmlghsamailing-listWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3S26TLPLVFAJTUN3VIXFDEBEXDYO22CEghsaWEB
News mentions
0No linked articles in our index yet.