GHSA-rf6f-7fwh-wjgh CVE-2026-33228
Prototype Pollution via parse() in NodeJS flatted
- Severity
- 8.9 / 10
- High · CVSS 4.0
- Exploit chance (EPSS)
- 0.84%
- Chance of exploitation in the next 30 days. Higher than 57.79% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-915 Improperly Controlled Modification of Dynamically-Determined Object Attributes
- CWE-1321 Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
- Fix
3.4.2- Upgrade flatted to this version or later
Description
Summary
The parse() function in flatted can use attacker-controlled string values from the parsed JSON as direct array index keys, without validating that they are numeric. Since the internal input buffer is a JavaScript Array, accessing it with the key "__proto__" returns Array.prototype via the inherited getter. This object is then treated as a legitimate parsed value and assigned as a property of the output object, effectively leaking a live reference to Array.prototype to the consumer. Any code that subsequently writes to that property will pollute the global prototype.
Root Cause
File: esm/index.js:29 (identical in cjs/index.js)
const resolver = (input, lazy, parsed, $) => output => {
for (let ke = keys(output), {length} = ke, y = 0; y < length; y++) {
const k = ke[y];
const value = output[k];
if (value instanceof Primitive) {
const tmp = input[value]; // Bug is here
No validation that value is a safe numeric index input is built as a plain Array. JavaScript's property lookup on arrays traverses the prototype chain for non-numeric keys. The key "__proto__" resolves to Array.prototype, which:
- has type "object" → passes the typeof tmp === object guard at line 30
- is not in the parsed Set yet → passes the !parsed.has(tmp) guard.
- The reference to Array.prototype is then enqueued in lazy and later unconditionally assigned to the output object.
Replication Steps
const Flatted = require('flatted');
const parsed = Flatted.parse('[{"x":"__proto__"}]');
parsed.x.polluted = 'pwned';
console.log([].polluted); // Returns true
Impact An attacker can supply a crafted flatted string to parse() that causes the returned object to hold a live reference to Array.prototype, enabling any downstream code that writes to that property to pollute the global prototype chain, potentially causing denial of service or code execution.
Recommended solution Validate that the index string represents an integer within the bounds of input before accessing it:
// Before (vulnerable) const tmp = input[value];
// After (safe) const idx = +value; // coerce boxed String → number const tmp = (Number.isInteger(idx) && idx >= 0 && idx < input.length) ? input[idx] : undefined;
Affected versions
npm
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
flatted npm → 3.4.2
- npm
npm install flatted@3.4.2- yarn
yarn add flatted@3.4.2- pnpm
pnpm add flatted@3.4.2
Severity breakdown
CVSS 4.0 8.9
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:P
- Attack vector
- Network
- Attack complexity
- Low
- Attack requirements
- None
- Privileges required
- None
- User interaction
- None
- Confidentiality (vulnerable system)
- High
- Integrity (vulnerable system)
- High
- Availability (vulnerable system)
- High
- Confidentiality (subsequent systems)
- None
- Integrity (subsequent systems)
- None
- Availability (subsequent systems)
- None
- Exploit maturity
- Proof of concept
CVSS 3.1 9.8
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Attack vector
- Network
- Attack complexity
- Low
- Privileges required
- None
- User interaction
- None
- Scope
- Unchanged
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Weakness
CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes
The product receives input from an upstream component that specifies multiple attributes, properties, or fields that are to be initialized or updated in an object, but it does not properly control which attributes can be modified.
How to prevent it
- Implementation: If available, use features of the language or framework that allow specification of allowlists of attributes or fields that are allowed to be modified. If possible, prefer allowlists over denylists. For applications written with Ruby on Rails, use the attr_accessible (allowlist) or attr_protected (denylist) macros in each class that may be used in mass assignment.
- Architecture and Design, Implementation: If available, use the signing/sealing features of the programming language to assure that deserialized data has not been tainted. For example, a hash-based message authentication code (HMAC) could be used to ensure that data has not been modified.
- Implementation: For any externally-influenced input, check the input against an allowlist of internal object attributes or fields that are allowed to be modified.
- Implementation, Architecture and Design: Refactor the code so that object attributes or fields do not need to be dynamically identified, and only expose getter/setter functionality for the intended attributes.
CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype.
How to prevent it
- Implementation: By freezing the object prototype first (for example, Object.freeze(Object.prototype)), modification of the prototype becomes impossible.
- Architecture and Design: By blocking modifications of attributes that resolve to object prototype, such as proto or prototype, this weakness can be mitigated.
- Implementation: When handling untrusted objects, validating using a schema can be used.
- Implementation: By using an object without prototypes (via Object.create(null) ), adding object prototype attributes by accessing the prototype via the special attributes becomes impossible, mitigating this weakness.
- Implementation: Map can be used instead of objects in most cases. If Map methods are used instead of object attributes, it is not possible to access the object prototype or modify it.
References
Advisories
Fixes and patches
Packages
Other links
- github.com/WebReflection/flatted/releases/tag/v3.4.2
- access.redhat.com/errata/RHSA-2026:13826
- access.redhat.com/errata/RHSA-2026:34342
- access.redhat.com/errata/RHSA-2026:9742
- access.redhat.com/security/cve/CVE-2026-33228
- bugzilla.redhat.com/show_bug.cgi
- security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-33228.json
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-25h7-pfq9-p65f flatted vulnerable to unbounded recursion DoS in parse() revive phase | High | Also affects flatted |
| GHSA-66wr-7vmr-p5jq Payload authentication token field handling issue | Critical | Same weakness, CWE-915 |
| EEF-CVE-2026-93477 Private action arguments can be set by user input on the bulk destroy and bulk update paths in Ash | Not rated yet | Same weakness, CWE-915 |
| GHSA-gx83-3vf8-gh7j jackson-databind: Comparable missing from DefaultBaseTypeLimitingValidator's unsafe base types (incomplete PolymorphicTypeValidator denylist) | Medium | Same weakness, CWE-915 |
| EEF-CVE-2026-78038 Job argument injection via :args overrides primary_key and tenant in AshOban | Not rated yet | Same weakness, CWE-915 |
| GHSA-265m-7826-wjqm Craft CMS: Authenticated RCE via `condition.config` JSON cleanse bypass | High | Same weakness, CWE-915 |
| GHSA-6vh2-wg4h-4vwj Flowise: Unauthenticated Property Injection into Flow Execution Context via Ungated `overrideConfig` Spread in Prediction API | Critical | Same weakness, CWE-915 |
| GHSA-vmjq-hvgq-2wv4 9router: Mass assignment in PATCH /api/settings allows authenticated authorization downgrade | High | Same weakness, CWE-915 |
Credits: yohannslm
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor