CVE-2026-40190: langsmith: prototype pollution enables auth bypass, RCE

GHSA-fw9q-39r9-c252 MEDIUM PoC AVAILABLE CISA: TRACK*
Published April 10, 2026
CISO Take

The LangSmith JavaScript/TypeScript SDK (npm ≤ 0.5.17) contains an incomplete prototype pollution fix in its vendored lodash `set()` function: the guard blocks `__proto__` mutation but leaves the `constructor.prototype` traversal path wide open, allowing any attacker who controls key names in data processed by the `createAnonymizer()` API to poison `Object.prototype` across the entire Node.js runtime. With 2,384 downstream npm dependents and a package risk score of 77/100, the blast radius spans a significant slice of JavaScript/TypeScript LLM tooling built on the LangChain ecosystem. No public exploit or CISA KEV entry exists today and the attack requires attacker-controlled input keys (AC:H), but in environments pairing LangSmith with Pug, EJS, or Handlebars template rendering, prototype pollution is a well-documented path to remote code execution — making the real-world severity higher than the CVSS 5.6 suggests. Upgrade to langsmith 0.5.18 immediately; if patching is blocked, add input validation at the anonymizer boundary to reject any keys containing the strings `constructor` or `prototype` before data reaches `createAnonymizer()`.

Sources: GitHub Advisory NVD ATLAS OpenSSF

What is the risk?

Rated Medium (CVSS 5.6) but the effective risk is higher in typical AI observability deployments. The AC:H rating requires attacker-controlled key names in anonymized data, which is a realistic condition in multi-tenant LangSmith tracing pipelines, API gateways that forward user-supplied JSON, or any LangChain application that logs external inputs. The prototype pollution root cause (CWE-1321) is well understood and PoC code ships in the advisory itself, lowering the exploitation bar to moderate. The 43 prior CVEs in the same package and an OpenSSF scorecard of 6.2/10 signal systemic supply chain hygiene concerns that elevate institutional risk beyond this single issue. For organizations using Node.js-based LLM pipelines, the authentication bypass impact alone justifies critical-tier internal prioritization despite the official Medium rating.

How does the attack unfold?

Malicious Input Crafting
Adversary constructs a JSON payload with keys following the `constructor.prototype.X` path pattern, ensuring string values match the target application's anonymizer regex (e.g., contain PII-like patterns).
AML.T0043.003
Anonymizer Trigger
The crafted payload is submitted to any endpoint that invokes `createAnonymizer()` on attacker-influenced data; the anonymizer's path extractor produces a dotted path traversing `constructor.prototype`.
AML.T0049
Prototype Pollution
The incomplete `baseAssignValue()` guard allows `set()` to write attacker-controlled values onto `Object.prototype`, poisoning all objects in the Node.js process for the remainder of its lifetime.
AML.T0010.001
Impact Realization
Polluted prototype properties propagate to all objects, enabling authentication bypass via truthy `isAdmin` checks, denial of service by overwriting `toString`/`valueOf`, or RCE through template engine sinks consuming polluted properties.
AML.T0106

What systems are affected?

Package Ecosystem Vulnerable Range Patched
LangChain npm <= 0.5.17 0.5.18
140.9K OpenSSF 5.8 2.9K dependents Pushed 5d ago 24% patched ~208d to patch Full package profile →

Do you use LangChain? You're affected.

How severe is it?

CVSS 3.1
5.6 / 10
EPSS
0.3%
chance of exploitation in 30 days
Higher than 23% of all CVEs
Exploitation Status
Exploit Available
Exploitation: MEDIUM
Sophistication
Moderate
Exploitation Confidence
medium
CISA SSVC: Public PoC
Public PoC indexed (trickest/cve)
Composite signal derived from CISA KEV, VulnCheck KEV, CISA SSVC, EPSS, Metasploit, Exploit-DB, trickest/cve, Nuclei templates, and inthewild.io exploitation reports.

What is the attack surface?

AV AC PR UI S C I A
AV Network
AC High
PR None
UI None
S Unchanged
C Low
I Low
A Low

What should I do?

5 steps
  1. PATCH

    Upgrade langsmith npm package to 0.5.18 or later across all Node.js services and CI/CD pipelines. Run npm audit or pnpm audit to identify transitive dependents.

  2. WORKAROUND (if patching is blocked): Add input sanitization before calling createAnonymizer() — reject or strip any object keys that equal constructor, prototype, or __proto__ before the data reaches the SDK.

  3. DETECTION

    Audit Node.js application logs for unexpected properties appearing on plain objects (e.g., log Object.getOwnPropertyNames(Object.prototype) at startup and periodically). Integrate --frozen-intrinsics Node.js flag where feasible to harden the prototype chain.

  4. SCANNING

    No Nuclei template is currently available; write a custom integration test that passes { 'constructor.prototype.canary': 'pwned' } through the anonymizer and checks ({}).canary post-call.

  5. DEPENDENCY HYGIENE

    The 43 CVEs in the same package and OpenSSF score of 6.2 warrant a broader supply chain review of all langchain-ai npm packages in use.

What does CISA's SSVC say?

Decision Track*
Exploitation poc
Automatable No
Technical Impact partial

Source: CISA Vulnrichment (SSVC v2.0). Decision based on the CISA Coordinator decision tree.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Art. 15 - Accuracy, robustness and cybersecurity for high-risk AI systems
ISO 42001
A.6.2.5 - AI system supply chain management
NIST AI RMF
GOVERN-6.1 - AI risk in supply chain, third party, and organizational policies
OWASP LLM Top 10
LLM05 - Supply Chain Vulnerabilities LLM07 - Insecure Plugin Design

Frequently Asked Questions

What is CVE-2026-40190?

The LangSmith JavaScript/TypeScript SDK (npm ≤ 0.5.17) contains an incomplete prototype pollution fix in its vendored lodash `set()` function: the guard blocks `__proto__` mutation but leaves the `constructor.prototype` traversal path wide open, allowing any attacker who controls key names in data processed by the `createAnonymizer()` API to poison `Object.prototype` across the entire Node.js runtime. With 2,384 downstream npm dependents and a package risk score of 77/100, the blast radius spans a significant slice of JavaScript/TypeScript LLM tooling built on the LangChain ecosystem. No public exploit or CISA KEV entry exists today and the attack requires attacker-controlled input keys (AC:H), but in environments pairing LangSmith with Pug, EJS, or Handlebars template rendering, prototype pollution is a well-documented path to remote code execution — making the real-world severity higher than the CVSS 5.6 suggests. Upgrade to langsmith 0.5.18 immediately; if patching is blocked, add input validation at the anonymizer boundary to reject any keys containing the strings `constructor` or `prototype` before data reaches `createAnonymizer()`.

Is CVE-2026-40190 actively exploited?

Proof-of-concept exploit code is publicly available for CVE-2026-40190, increasing the risk of exploitation.

How to fix CVE-2026-40190?

1. PATCH: Upgrade langsmith npm package to 0.5.18 or later across all Node.js services and CI/CD pipelines. Run `npm audit` or `pnpm audit` to identify transitive dependents. 2. WORKAROUND (if patching is blocked): Add input sanitization before calling `createAnonymizer()` — reject or strip any object keys that equal `constructor`, `prototype`, or `__proto__` before the data reaches the SDK. 3. DETECTION: Audit Node.js application logs for unexpected properties appearing on plain objects (e.g., log `Object.getOwnPropertyNames(Object.prototype)` at startup and periodically). Integrate `--frozen-intrinsics` Node.js flag where feasible to harden the prototype chain. 4. SCANNING: No Nuclei template is currently available; write a custom integration test that passes `{ 'constructor.prototype.canary': 'pwned' }` through the anonymizer and checks `({}).canary` post-call. 5. DEPENDENCY HYGIENE: The 43 CVEs in the same package and OpenSSF score of 6.2 warrant a broader supply chain review of all langchain-ai npm packages in use.

What systems are affected by CVE-2026-40190?

This vulnerability affects the following AI/ML architecture patterns: LangChain JS/TS agent frameworks, LLM observability and tracing pipelines, AI data anonymization and PII redaction pipelines, Multi-tenant AI API gateways, LangGraph workflow orchestration.

What is the CVSS score for CVE-2026-40190?

CVE-2026-40190 has a CVSS v3.1 base score of 5.6 (MEDIUM). The EPSS exploitation probability is 0.31%.

What is the AI security impact?

Affected AI Architectures

LangChain JS/TS agent frameworksLLM observability and tracing pipelinesAI data anonymization and PII redaction pipelinesMulti-tenant AI API gatewaysLangGraph workflow orchestration

MITRE ATLAS Techniques

AML.T0010.001 AI Software
AML.T0043.003 Manual Modification
AML.T0049 Exploit Public-Facing Application
AML.T0106 Exploitation for Credential Access

Compliance Controls Affected

EU AI Act: Art. 15
ISO 42001: A.6.2.5
NIST AI RMF: GOVERN-6.1
OWASP LLM Top 10: LLM05, LLM07

What are the technical details?

Original Advisory

# GHSA-fw9q-39r9-c252: Prototype Pollution via Incomplete Lodash `set()` Guard in `langsmith-sdk` **Severity:** Medium (CVSS ~5.6) **Status:** Fixed in 0.5.18 --- ## Summary The LangSmith JavaScript/TypeScript SDK (`langsmith`) contains an incomplete prototype pollution fix in its internally vendored lodash `set()` utility. The `baseAssignValue()` function only guards against the `__proto__` key, but fails to prevent traversal via `constructor.prototype`. This allows an attacker who controls keys in data processed by the `createAnonymizer()` API to pollute `Object.prototype`, affecting all objects in the Node.js process. --- ## Affected Products | Product | Affected Versions | Component | |---------|-------------------|-----------| | `langsmith` (npm) | <= 0.5.17 | `js/src/utils/lodash/baseAssignValue.ts`, `js/src/anonymizer/index.ts` | | langchain-ai/langsmith-sdk | GitHub main branch (as of 2026-03-24) | JS/TypeScript SDK | **Not affected:** The Python SDK (`langsmith` on PyPI) does not use lodash or an equivalent pattern. --- ## Root Cause The SDK vendors an internal copy of lodash's `set()` function at `js/src/utils/lodash/`. The `baseAssignValue()` function at `baseAssignValue.ts:11` implements a guard for prototype pollution: ```typescript function baseAssignValue(object: Record<string, any>, key: string, value: any) { if (key === "__proto__") { Object.defineProperty(object, key, { configurable: true, enumerable: true, value: value, writable: true, }); } else { object[key] = value; // ← No guard for "constructor" or "prototype" keys } } ``` This blocks `__proto__` pollution but does **not** block the `constructor.prototype` traversal path. When `set()` is called with a path like `"constructor.prototype.polluted"`: 1. `castPath()` splits it into `["constructor", "prototype", "polluted"]` 2. `baseSet()` iterates: `obj.constructor` → `Object` → `Object.prototype` 3. `assignValue(Object.prototype, "polluted", value)` calls `baseAssignValue()` 4. Key is `"polluted"` (not `"__proto__"`), so the guard is bypassed 5. `Object.prototype.polluted = value` — all objects are polluted --- ## Attack Vector via Anonymizer The `createAnonymizer()` API (importable as `langsmith/anonymizer`) processes data by: 1. **Extracting string nodes** — `extractStringNodes()` walks an object recursively and builds dotted paths from keys 2. **Applying regex replacements** — If a string value matches a configured pattern, the node is marked for update (`anonymizer/index.ts:95`) 3. **Writing back with `set()`** — `set(mutateValue, node.path, node.value)` writes the replaced value back (`anonymizer/index.ts:123`) An attacker who controls keys in data being anonymized can construct a nested object where the path resolves to `constructor.prototype.X`: ```javascript { wrapper: { "constructor.prototype.isAdmin": "contains-secret-pattern" } } ``` `extractStringNodes()` produces path `"wrapper.constructor.prototype.isAdmin"`. When the replacement triggers and `set()` writes back, it traverses up to `Object.prototype`. Although `createAnonymizer()` uses `deepClone()` at `anonymizer/index.ts:62` (`JSON.parse(JSON.stringify(data))`), the prototype chain traversal escapes the clone boundary because `clone.wrapper.constructor` resolves to the global `Object` constructor, not a cloned copy. --- ## Proof of Concept ```javascript import { createAnonymizer } from "langsmith/anonymizer"; const anonymizer = createAnonymizer([ { pattern: "secret", replace: "[REDACTED]" } ]); console.log("BEFORE:", ({}).isAdmin); // undefined const maliciousInput = { wrapper: { "constructor.prototype.isAdmin": "this-is-secret-data" } }; anonymizer(maliciousInput); console.log("AFTER:", ({}).isAdmin); // "this-is-[REDACTED]-data" console.log("Array:", [].isAdmin); // "this-is-[REDACTED]-data" function checkAccess(user) { if (user.isAdmin) return "ACCESS GRANTED"; return "ACCESS DENIED"; } console.log(checkAccess({ name: "bob" })); // "ACCESS GRANTED" ← BYPASSED ``` --- ## Impact Prototype pollution in a Node.js process can enable: 1. **Authentication bypass** — `if (user.isAdmin)` checks succeed on all objects 2. **Remote Code Execution** — Exploitable in template engines (Pug, EJS, Handlebars, Nunjucks) via polluted prototype properties that reach `eval()`/`Function()` sinks 3. **Denial of Service** — Overwriting `toString`, `valueOf`, or `hasOwnProperty` on all objects 4. **Data exfiltration** — Polluting serialization methods to inject attacker-controlled values --- ## Remediation In `baseAssignValue.ts`, extend the guard to cover `constructor` and `prototype` keys: ```typescript function baseAssignValue(object, key, value) { if (key === "__proto__" || key === "constructor" || key === "prototype") { Object.defineProperty(object, key, { configurable: true, enumerable: true, value, writable: true, }); } else { object[key] = value; } } ``` As defense in depth, `extractStringNodes()` in `anonymizer/index.ts` should also sanitize or reject path segments matching `constructor` or `prototype` before passing them to `set()`. --- ## Timeline | Date | Event | |------|-------| | 2026-03-24 | Initial report submitted | | 2026-04-09 | Vendor confirmed; fixed in 0.5.18 | --- ## Credits Reported by: OneThing4101

Exploitation Scenario

An adversary targeting a SaaS platform that uses LangChain.js with LangSmith tracing to log and redact user conversation data submits an API request where the conversation payload includes field names crafted as `constructor.prototype.isAdmin`. The LangSmith anonymizer's `extractStringNodes()` walks the object, constructs the dotted path `wrapper.constructor.prototype.isAdmin`, finds the string value matches the PII regex (e.g., it contains a pattern like an email), marks it for replacement, and calls `set(clone, 'wrapper.constructor.prototype.isAdmin', '[REDACTED]')`. The `baseAssignValue()` guard only checks for `__proto__`, so the traversal reaches `Object.prototype.isAdmin = '[REDACTED]'`. From this point forward, every access control check of the form `if (req.user.isAdmin)` in the same Node.js process evaluates to truthy for all users, granting universal admin access. In a LangGraph-based platform also rendering HTML via a template engine, the adversary can escalate to RCE by polluting properties consumed in template rendering contexts.

Weaknesses (CWE)

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.

  • [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.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L

Timeline

Published
April 10, 2026
Last Modified
April 10, 2026
First Seen
April 11, 2026

Related Vulnerabilities