CVE-2025-13465: Verified Repro With Script Download
CVE-2025-13465: lodash: prototype pollution in .unset/ .omit deletes global prototype methods
CVE-2025-13465 is verified against lodash · npm. Affected versions: >= 4.0.0, <= 4.17.22. Fixed in 4.17.23. Vulnerability class: Prototype Pollution. This medium reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00134.
What Is CVE-2025-13465?
CVE-2025-13465 (GHSA-xxjr-mmjv-4gpg) is a medium-severity prototype-pollution-by-deletion vulnerability (CWE-1321) in lodash's _.unset and _.omit functions. Pruva reproduced it (reproduction REPRO-2026-00134).
CVE-2025-13465 Severity & CVSS Score
CVE-2025-13465 is rated medium severity, with a CVSS base score of 5.3 out of 10.
Medium — meaningful risk under specific conditions. Schedule a fix in the normal cycle.
Affected lodash Versions
lodash · npm versions >= 4.0.0, <= 4.17.22 are affected.
How to Reproduce CVE-2025-13465
pruva-verify REPRO-2026-00134 curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00134/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2025-13465
Reproduced by Pruva's autonomous agents — 149 tool calls over 29 min. Full root-cause analysis and the complete transcript are below.
How the agent worked
Root Cause and Exploit Chain for CVE-2025-13465
Summary
CVE-2025-13465 is a prototype-pollution-by-deletion vulnerability in lodash's _.unset and _.omit functions. When a user-controlled string path containing __proto__ is passed to these functions, lodash traverses into Object.prototype and deletes the targeted property globally. This affects every object in the Node.js process, causing denial-of-service or integrity degradation. The issue is fixed in lodash 4.17.23 by adding a guard in baseUnset that rejects dangerous string path segments (__proto__, constructor.prototype).
Impact
- Package:
lodash(npm) - Affected versions: 4.0.0 through 4.17.22 (inclusive)
- Fixed version: 4.17.23
- Risk level: Moderate (CVSS 3.1 base 5.3)
- Consequences: Any application that forwards attacker-controlled key names into
_.unsetor_.omit(e.g., from JSON request input) can have built-in prototype methods deleted globally, leading to denial-of-service or unexpected behavior across the entire process.
Root Cause
The root cause lies in the baseUnset function (shared by _.unset and _.omit). Before the fix, baseUnset parsed the path string into segments and walked each segment on the target object without validating whether a segment was a dangerous prototype accessor such as __proto__, constructor, or prototype.
Because someObject.__proto__ returns the live Object.prototype, a crafted path like __proto__.toString causes the function to traverse out of the intended object and into the global prototype, then delete the specified key from it.
Fix commit: edadd452146f7e4bad4ea684e955708931d84d81
The fix adds a loop in baseUnset that iterates over path segments and:
- Skips non-string keys.
- Blocks
__proto__anywhere in the path if it is not an own property of the current object. - Blocks
constructor.prototypechains, with a narrow exception for primitive roots (e.g.,_.unset(0, 'constructor.prototype.a')).
Reproduction Steps
The reproduction script is repro/reproduction_steps.sh.
What the script does:
- Installs the last published vulnerable version (
lodash@4.17.21) in a temporary directory. - Runs a Node.js harness (
test_app.js) that simulates an application receiving untrusted user input (__proto__.toString) and passing it to_.unset({}, untrustedInput). - Captures the
typeof Object.prototype.toStringbefore and after the call. - Repeats steps 1–3 with the fixed version (
lodash@4.17.23). - Also runs a secondary check with
_.omit({}, '__proto__.toString')on the vulnerable build. - Writes a JSON runtime manifest (
repro/runtime_manifest.json) with versions, exit codes, log paths, and explicit confirmation markers.
Expected evidence of reproduction:
- Vulnerable build:
typeof Object.prototype.toStringchanges from"function"to"undefined", and the harness exits with code2emittingVULN_CONFIRMED. - Fixed build:
typeof Object.prototype.toStringstays"function", and the harness exits with code0emittingFIX_CONFIRMED.
Evidence
Log files captured by the script:
logs/vuln_unset.log— Vulnerable_.unsettest output.logs/fixed_unset.log— Fixed_.unsettest output.logs/vuln_omit.log— Vulnerable_.omittest output.repro/runtime_manifest.json— Structured manifest linking all evidence.
Key excerpts from logs/vuln_unset.log:
lodash version: 4.17.21
untrusted path input: __proto__.toString
typeof Object.prototype.toString BEFORE: function
typeof Object.prototype.toString AFTER: undefined
VULN_CONFIRMED: prototype pollution via _.unset in lodash 4.17.21
Key excerpts from logs/fixed_unset.log:
lodash version: 4.17.23
untrusted path input: __proto__.toString
typeof Object.prototype.toString BEFORE: function
typeof Object.prototype.toString AFTER: function
FIX_CONFIRMED: prototype intact in lodash 4.17.23
Key excerpts from logs/vuln_omit.log:
lodash version: 4.17.21
typeof Object.prototype.toString BEFORE: function
typeof Object.prototype.toString AFTER: undefined
VULN_CONFIRMED_OMIT: _.omit pollutes prototype
Environment:
- Node.js v22.22.2
- npm 10.9.7
Recommendations / Next Steps
- Upgrade guidance: Projects using lodash 4.17.21 or earlier should upgrade to 4.17.23 or later immediately. Note that a separate array-path bypass (CVE-2026-2950) exists and is fixed in 4.18.0, so upgrading to 4.18.0+ is recommended for full protection.
- Code review: Audit all calls to
_.unsetand_.omitthat accept user-controlled path strings. If upgrading is not immediately possible, sanitize path segments to reject__proto__,constructor, andprototypebefore passing them to lodash. - Testing: Add regression tests that exercise
__proto__andconstructor.prototypepaths against_.unsetand_.omitto prevent future regressions.
Additional Notes
- Idempotency:
repro/reproduction_steps.shhas been executed twice consecutively with identical results (exit 0, same log outputs). - Version caveat: The ticket specifies 4.17.22 as the last vulnerable version, but this version was never published to npm or tagged in Git. The reproduction uses
4.17.21as the vulnerable baseline because it is the last published version that exhibits the flaw. The fix commitedadd452is included in4.17.23, which is published and confirmed to block the attack. - Edge cases: The fix specifically targets string path segments. A later bypass using array paths (
['__proto__', 'toString']) was assigned a separate CVE (CVE-2026-2950) and is out of scope for this ticket.
CVE-2025-13465 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.
git clone --depth=200 https://github.com/lodash/lodash.git /tmp/lodash_repro 2>&1 | tail -5Cloning into '/tmp/lodash_repro'...
cd /tmp/lodash_repro && git show edadd452146f7e4bad4ea684e955708931d84d81 --statcommit edadd452146f7e4bad4ea684e955708931d84d81
Author: Ulises Gascón <ulisesgascongonzalez@gmail.com>
Date: Fri Dec 5 19:26:49 2025 +0100
Prevent prototype pollution on baseUnset function
* test: add tests to prevent security regressions
cd /tmp/lodash_repro && git show edadd452146f7e4bad4ea684e955708931d84d81 -- lodash.js | head -100{"cwd":"/root/.pruva/runs/cve-2025-13465_20260522-075758","duration_ms":12,"exit_code":0,"stderr":"","stdout":"commit edadd452146f7e4bad4ea684e955708931d84d81\nAuthor: Ulises Gascón <ulisesgascongonzalez@gmail.com>\nDate: Fri Dec 5 19:26:49 2025 +0100\n\n Prevent prototype pollution on baseUnset function\n \n * test: add tests to prevent security regressions\n \n * sec: prevent prototype pollution on `baseUnset` function\n \n * chore: improve security patch\n \n - Expand both `_.omit` & `_.unset` security tests to loop over `__proto__`, `constructor`, `prototype`\n - Only block `__proto__` if not an own property\n\ndiff --git a/lodash.js b/lodash.js\nindex 1d232ac..900cedf 100644\n--- a/lodash.js\n+++ b/lodash.js\n@@ -4370,8 +4370,47 @@\n */\n function baseUnset(object, path) {\n path = castPath(path, object);\n- object = parent(object, path);\n- return object == null || delete object[toKey(last(path))];\n+\n+ // Prevent prototype pollution, see: https://github.com/lodash/lodash/security/advisories/GHSA-xxjr-mmjv-4gpg\n+ var index = -1,\n+ length = path.length;\n+\n+ if (!length) {\n+ return tru… [truncated]Artifacts and Evidence for CVE-2025-13465
Scripts, logs, diffs, and output captured during the reproduction.
No artifacts available
How to Fix CVE-2025-13465
Upgrade lodash · npm to 4.17.23 or later.
FAQ: CVE-2025-13465
How does the CVE-2025-13465 prototype-pollution attack work?
Which lodash versions are affected by CVE-2025-13465, and where is it fixed?
How severe is CVE-2025-13465?
How can I reproduce CVE-2025-13465?
References for CVE-2025-13465
Authoritative sources for CVE-2025-13465 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.