@graphql-tools/utils: Prototype pollution in mergeIncrementalResult
A prototype pollution vulnerability in @graphql-tools/utils allows an attacker to inject arbitrary properties into Object.prototype via unvalidated path segments in incremental GraphQL responses.
Triage facts
Revision 1- Applicability
- @graphql-tools/utils (>= 10.10.1, <= 12.0.1)
- Evidence
- Unknown
- Severity
- High
- Action
- Elevated
- Sources
- 1 public source
- Freshness
- Revision 1Oct 26, 16:13 UTC
- Source quality
- A1Likely
The @graphql-tools/utils package (versions 10.10.1 through 12.0.1) contains a prototype pollution vulnerability in the mergeIncrementalResult function. The function incorrectly validates path segments by using strict equality checks (===) against forbidden keys like '__proto__', 'constructor', and 'prototype'. Because the function does not verify that these path segments are primitive types (strings or numbers), an attacker can supply an object, such as an array ["__proto__"]. In JavaScript, this is coerced into the string "__proto__" during property access, successfully bypassing the protection check and allowing the attacker to write values onto Object.prototype. This can lead to authorization bypass, configuration manipulation, or unexpected application behavior in any consuming Node.js process.
Attack Chain
- An attacker gains control over, or performs a MITM attack on, an upstream GraphQL subgraph or transport layer.
- The attacker crafts a malicious incremental GraphQL response (such as an
@deferor@streampatch). - The attacker sets the
pathfield in the response to include a non-primitive, array-based segment:[["__proto__"], "maliciousKey"]. - The consuming application receives the malicious response and passes it to the public
mergeIncrementalResulthelper. mergeIncrementalResultcallssetObjectKeyPath, which checks the array["__proto__"]against the forbidden strings; the check fails (returning false) because the types do not match, allowing the segment to proceed.- During assignment,
current[key]triggersToPropertyKeycoercion, converting the array to the string"__proto__". - The function resolves
Object.prototypeand assigns the attacker's value to the chosen key. - Unrelated objects created subsequently in the Node.js process inherit the polluted property, altering application logic.
Impact
An attacker can overwrite properties on Object.prototype, potentially impacting global application security controls (e.g., overriding isAdmin flags or configuration objects). This effect persists for the lifetime of the Node.js process and applies to all objects instantiated after the pollution event, escaping the scope of the original GraphQL response.
Recommendation
- Upgrade
@graphql-tools/utilsto a patched version once available, or implement a wrapper to validate that all path segments are strictly primitive strings or numbers before callingmergeIncrementalResult. - Use
Object.freeze(Object.prototype)in the consuming Node.js application to mitigate the impact of prototype pollution attempts. - Implement runtime input validation on all upstream data sources that provide incremental GraphQL responses.
Immediate actions
Audit Node.js applications utilizing @graphql-tools/utils for processing external or untrusted GraphQL incremental responses.
Threat Hunt
Identify applications using @graphql-tools/utils that consume untrusted GraphQL incremental responses.
Data: Application dependency manifests (package.json), Code audit for usage of mergeIncrementalResult
Mitigations
Implement primitive-type validation for path segments before calling mergeIncrementalResult.
Prototype pollution in @graphql-tools/utils