CVE-2026-8657: Verified Repro With Script Download
CVE-2026-8657: jsondiffpatch: prototype pollution via crafted delta in patch
CVE-2026-8657 is verified against jsondiffpatch · npm. Affected versions: < 0.7.6. Fixed in 0.7.6. Vulnerability class: Prototype Pollution. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00135.
What Is CVE-2026-8657?
CVE-2026-8657 is a high-severity prototype pollution vulnerability (CWE-1321) in the jsondiffpatch npm package's patch(), unpatch(), reverse(), and JSON Patch formatter patch() functions. Pruva reproduced it (reproduction REPRO-2026-00135).
CVE-2026-8657 Severity & CVSS Score
CVE-2026-8657 is rated high severity, with a CVSS base score of 8.2 out of 10.
High — serious impact or readily exploitable. Prioritize remediation.
Affected jsondiffpatch Versions
jsondiffpatch · npm versions < 0.7.6 are affected.
How to Reproduce CVE-2026-8657
pruva-verify REPRO-2026-00135 curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00135/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-8657
Reproduced by Pruva's autonomous agents — 144 tool calls over 23 min. Full root-cause analysis and the complete transcript are below.
How the agent worked
Root Cause and Exploit Chain for CVE-2026-8657
Summary
jsondiffpatch versions before 0.7.6 are vulnerable to prototype pollution in patch(), unpatch(), reverse(), and the JSON Patch formatter's patch(). When applying a delta or JSON Patch document, the library traverses the target object using attacker-controlled property names and path segments without rejecting dangerous keys such as __proto__ or constructor.prototype. This allows an attacker to write arbitrary values into Object.prototype, affecting every plain object in the running Node.js process.
Impact
- Package:
jsondiffpatch(npm) - Repository: https://github.com/benjamine/jsondiffpatch
- Affected versions:
< 0.7.6 - Fixed version:
0.7.6 - CWE: CWE-1321 (Prototype Pollution)
- Severity: High (CVSS 3.1 base 8.2)
Any code that forwards an attacker-influenced delta or JSON Patch into jsondiffpatch.patch() or the jsonpatch formatter's patch() (for example, a delta deserialized from untrusted JSON request input) can be exploited to pollute the global prototype.
Root Cause
The root cause lies in two places in the vulnerable code (v0.7.5):
packages/jsondiffpatch/src/filters/nested.ts: ThepatchFilter,collectChildrenPatchFilter,reverseFilter, andcollectChildrenReverseFilterfunctions iterate over delta keys and patch children using property names taken directly from the delta. They do not reject__proto__or guard against inherited properties likeconstructor.prototype. For example:for (const name in objectDelta) { const child = new PatchContext( (context.left as Record<string, unknown>)[name], objectDelta[name], ); context.push(child, name); }When
nameis__proto__,context.left.__proto__resolves toObject.prototype, causing writes to the global prototype.packages/jsondiffpatch/src/formatters/jsonpatch-apply.ts: TheparsePathFromRFC6902()function splits JSON Pointer paths into segments without validating them. When a segment is__proto__, the subsequentadd()orreplace()operations write intoObject.prototype.
The fix commit 381c0125efab49f6f0dbc08317d01d55717672af addresses this by:
- Introducing an
UNSAFE_KEYSset containing__proto__(andconstructor/prototypefor the JSON Patch formatter). - Skipping delta keys that match unsafe names in all patch/unpatch/reverse filters.
- Using
Object.prototype.hasOwnProperty.call(left, name)to prevent traversal into inherited properties (mitigatingconstructor.prototypeattacks). - Adding validation in
parsePathFromRFC6902()that throws for unsafe path segments in JSON Patch operations.
Reproduction Steps
The reproduction script is repro/reproduction_steps.sh. It performs the following steps:
- Installs
jsondiffpatch@0.7.5(vulnerable) andjsondiffpatch@0.7.6(fixed) in separate scratch directories. - Runs a shared ES module test against each installation.
- The test attempts five prototype-pollution vectors:
jsondiffpatch.patch()with a delta containing__proto__jsondiffpatch.patch()with a delta containingconstructor.prototypejsonpatchFormatter.patch()with anaddoperation targeting/__proto__/pp3jsonpatchFormatter.patch()with areplaceoperation targeting/__proto__/pp4jsondiffpatch.unpatch()with a delta containingconstructor.prototype
- After each attempt, the test checks whether a plain
{}inherits the injected property. If so, it logs the polluted property names. - The script verifies:
- Vulnerable version (0.7.5): prints
VULNERABLEand exits0 - Fixed version (0.7.6): prints
NOT_VULNERABLEand exits1
- Vulnerable version (0.7.5): prints
Evidence
Vulnerable test log:
logs/test_vuln.log=== Testing vulnerable version 0.7.5 === POLLUTED patch_proto: pp1 POLLUTED patch_constructor: pp2 POLLUTED jsonpatch_add: pp3 POLLUTED jsonpatch_replace: pp4 VULNERABLEFixed test log:
logs/test_fixed.log=== Testing fixed version 0.7.6 === NOT_VULNERABLERuntime manifest:
repro/runtime_manifest.json(written on successful reproduction)Environment: Node.js v22.22.2,
jsondiffpatch@0.7.5and@0.7.6installed via npm.
Recommendations / Next Steps
- Upgrade immediately to
jsondiffpatch >= 0.7.6. - Input validation: If you must accept deltas or JSON Patches from untrusted sources, validate them independently before passing them to
jsondiffpatch.patch()or the JSON Patch formatter. - Regression testing: Include the provided test cases in your CI pipeline to guard against future regressions. The upstream project has added 7 regression tests covering all attack vectors.
- Runtime hardening: Consider using
Object.freeze(Object.prototype)or libraries likesafe-object-assignto make prototype pollution harder to exploit in production environments.
Additional Notes
- Idempotency: The reproduction script was run twice consecutively with identical results.
- Edge cases: The fix intentionally preserves legitimate use cases (e.g., objects that have their own
constructorproperty). The upstream test suite includes a dedicated test (should still correctly patch objects with a legitimate 'constructor' own property) confirming this. - Scope: While the reproduction focuses on
patch()andjsonpatchFormatter.patch(), the fix also protectsunpatch()andreverse()because they share the same traversal logic.
CVE-2026-8657 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
cd /root/.pruva/runs/cve-2026-8657_20260522-090918 && git clone --depth 100 https://github.com/benjamine/jsondiffpatch.git external/jsondiffpatchCloning into 'external/jsondiffpatch'...
cd /root/.pruva/runs/cve-2026-8657_20260522-090918/external/jsondiffpatch && git show 381c0125efab49f6f0dbc08317d01d55717672af{"cwd":"/root/.pruva/runs/cve-2026-8657_20260522-090918","duration_ms":5,"exit_code":0,"stderr":"","stdout":"commit 381c0125efab49f6f0dbc08317d01d55717672af\nAuthor: Benjamín Eidelman <beneidel+gh@gmail.com>\nDate: Thu May 14 19:54:04 2026 -0300\n\n fix: prevent prototype pollution in patch, unpatch, reverse, and JSON Patch apply\n \n Block __proto__ keys in nested delta patch/reverse filters; guard against\n traversal into non-own properties (constructor.prototype attack); silently\n skip JSON Patch add ops targeting unsafe path segments. Adds 7 regression\n tests covering all attack vectors (jsondiffpatch.patch, unpatch, reverse,\n and jsonpatch formatter).\n\ndiff --git a/packages/jsondiffpatch/src/filters/nested.ts b/packages/jsondiffpatch/src/filters/nested.ts\nindex a4e06fb..75b06aa 100644\n--- a/packages/jsondiffpatch/src/filters/nested.ts\n+++ b/packages/jsondiffpatch/src/filters/nested.ts\n@@ -3,6 +3,13 @@ import PatchContext from \"../contexts/patch.js\";\n import ReverseContext from \"../contexts/reverse.js\";\n import type { ArrayDelta, Delta, Filter, ObjectDelta } from \"../types.js\";\n \n+// '__proto__' must never be used as a property key — it… [truncated]Artifacts and Evidence for CVE-2026-8657
Scripts, logs, diffs, and output captured during the reproduction.
No artifacts available
How to Fix CVE-2026-8657
Upgrade jsondiffpatch · npm to 0.7.6 or later.
FAQ: CVE-2026-8657
How does the CVE-2026-8657 prototype-pollution attack work?
__proto__; since someObject.__proto__ is the live Object.prototype, passing that delta into jsondiffpatch.patch() (or the JSON Patch formatter's patch()) lets the traversal step outside the intended target object and assign an attacker-chosen value directly onto Object.prototype, polluting every plain object for the rest of the Node.js process.Which jsondiffpatch versions are affected by CVE-2026-8657, and where is it fixed?
How severe is CVE-2026-8657?
How can I reproduce CVE-2026-8657?
__proto__ into patch() (or the JSON Patch formatter) and confirms Object.prototype is polluted with the attacker-chosen value in the running Node.js process.References for CVE-2026-8657
Authoritative sources for CVE-2026-8657 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.