CVE-2026-40190 [Deep Dive]: AI Prototype Pollution
Bottom Line
The direct bug in langsmith was rated medium, but the real lesson is architectural: in AI orchestration stacks, prototype pollution is rarely the last bug in the chain. Once polluted state reaches tracing, HTTP clients, plugins, or agent tools, low-level object corruption can become a high-impact compromise path.
Key Takeaways
- ›The public record matching this issue class is CVE-2026-40190, published on April 10, 2026.
- ›langsmith versions up to 0.5.17 were affected; the fix landed in 0.5.18.
- ›The root cause was an incomplete proto guard that still allowed constructor.prototype traversal.
- ›Prototype pollution in AI stacks matters because it chains into logging, redaction, MCP, and outbound HTTP behavior.
- ›A separate April 2026 Axios advisory showed how polluted state can escalate into much larger impact in Node.js apps.
One important correction up front: as of May 03, 2026, I could not locate a public NVD or GitHub advisory for CVE-2026-7781 matching this issue. The public, verifiable LangChain-adjacent prototype-pollution record is CVE-2026-40190, published on April 10, 2026, affecting the JavaScript/TypeScript LangSmith SDK. That still makes this a useful case study for common AI orchestration frameworks, because the bug sits in exactly the kind of tracing, redaction, and data-plumbing layer that modern agent stacks rely on.
- The bug affected langsmith on npm through 0.5.17 and was fixed in 0.5.18.
- The vulnerable flow passed attacker-influenced object paths into an internal lodash-style set() helper.
- The guard blocked proto but missed constructor.prototype, which is a classic prototype-pollution bypass.
- NVD lists the CNA score as CVSS 5.6 Medium, but chainability makes the operational risk higher in real AI systems.
CVE Summary Card
Bottom Line
Treat this as more than a tracing bug. In Node-based AI stacks, prototype pollution can move laterally into agent state, policy checks, outbound requests, and plugin execution paths.
| Field | Value |
|---|---|
| CVE | CVE-2026-40190 |
| Published | April 10, 2026 |
| Affected package | langsmith npm package |
| Affected versions | <= 0.5.17 |
| Fixed version | 0.5.18 |
| CWE | CWE-1321 prototype pollution |
| Entry point | createAnonymizer() processing attacker-controlled object keys |
| Primary bypass | constructor.prototype traversal |
| Direct impact | Process-wide object pollution in Node.js |
| Why AI teams should care | Tracing, anonymization, tool metadata, and workflow state often share the same object graph |
The advisory describes an incomplete protection in an internally vendored lodash-style utility. Instead of eliminating dangerous path segments entirely, the code handled one dangerous property name and left another traversal route intact. That detail matters because AI infrastructure code is full of nested objects: prompts, tool arguments, model responses, run metadata, safety annotations, and observability envelopes all move through the same generic helpers.
That is why this bug deserves attention beyond LangSmith itself. A modern orchestration framework is not just an agent loop. It is a graph of serializers, redactors, HTTP clients, retrievers, plugin adapters, and execution state. Pollution in one utility can quietly taint every one of those layers.
Vulnerable Code Anatomy
Where the flaw lived
According to the public advisory, the vulnerable path involved two pieces working together:
- extractStringNodes() recursively walked input objects and constructed dotted key paths.
- set() wrote transformed values back into the cloned object.
The bug was not that the SDK accepted nested objects. The bug was that it reconstructed write paths from attacker-controlled keys and then trusted a partial prototype guard inside the write helper. Conceptually, the dangerous pattern looked like this:
for each discovered nodePath in inputObject:
if replacementRuleMatches(nodeValue):
safeClone = clone(data)
setPath(safeClone, nodePath, redactedValue)That pattern is common in AI stacks. Redaction engines, metadata normalizers, audit log scrubbers, and workflow state updaters all do some variation of it.
Why the guard failed
The advisory states that the internal baseAssignValue() logic explicitly guarded proto but did not prevent traversal through constructor.prototype. In practical terms, that means the code defended against the obvious payload and missed the more resilient route. Once the path walker resolves constructor to the global object constructor and then reaches prototype, the final write lands on Object.prototype.
That is the critical mental model:
- The exploit does not need to replace the whole object.
- It only needs one path segment chain that escapes the local object boundary.
- After that, the mutation becomes process-wide state.
Even the defensive clone did not save the design. Cloning protects data ownership; it does not protect the prototype chain if later writes can intentionally traverse into shared built-ins.
Attack Timeline
The public timeline is short but instructive:
- March 24, 2026: Initial report submitted, per the OSV entry.
- April 9, 2026: Vendor confirmed the issue and fixed it in 0.5.18.
- April 10, 2026: CVE-2026-40190 was published and added to NVD.
- April 16, 2026: OSV metadata shows a later modification timestamp, reflecting follow-up record updates.
On its own, that looks like a normal open-source disclosure cycle. The more important timeline context came from elsewhere in the Node ecosystem the same week. A separate GitHub advisory for Axios, published on April 9, 2026, documented how prototype pollution in any third-party dependency could be escalated into a request-smuggling and cloud-compromise gadget chain. In other words, the industry reminder arrived almost simultaneously: prototype pollution is no longer “just” a weird JavaScript edge case.
For AI teams, that timing matters because orchestration apps routinely combine all of the following:
- Node.js runtime behavior built around flexible objects.
- Outbound HTTP clients such as Axios.
- User-supplied metadata, tool schemas, or trace payloads.
- Dynamic graph execution and plugin adapters.
Once those ingredients coexist, a medium-severity primitive can become a high-consequence chain.
Exploitation Walkthrough
What an attacker needs
This issue is best understood as a three-stage conceptual chain rather than a single dramatic exploit:
- The attacker gains control over object keys that enter a redaction or anonymization flow.
- The framework rebuilds those keys into dotted paths and writes them back with a generic setter.
- The polluted property later influences unrelated logic somewhere else in the process.
That last step is the one teams underestimate. Pollution usually does not look exciting at the moment it happens. The damage shows up later when some innocent-looking code checks a property, merges headers, serializes a request, or evaluates a template.
How it plays out in AI orchestration stacks
A conceptual workflow might look like this:
- A public-facing chat or API route accepts task metadata, tool inputs, or run annotations.
- The application sends those objects into a tracing or privacy layer for redaction before storage.
- The redaction layer mutates the object using attacker-derived keys.
- A polluted property now exists on shared prototypes.
- Later code in the same process consumes that property during authorization, routing, or HTTP request construction.
No working proof-of-concept is required to see the risk. If your stack mixes user-controlled structure with generic object-path mutation, you have created a pollution sink. If you also depend on dynamic behavior later in the request lifecycle, you have created a gadget surface.
This is where contextual controls matter. Before shipping new redaction rules into observability pipelines, validate the behavior in a controlled environment like TechBytes’ Data Masking Tool so you can verify that replacement logic does not rely on unsafe path reconstruction or unexpected object traversal.
Hardening Guide
Immediate remediation
- Upgrade langsmith to 0.5.18 or later.
- Inventory every service that imports langsmith/anonymizer or equivalent redaction helpers.
- Rebuild lockfiles and container images; do not assume a semver range already pulled the patch.
- Search for vendored or copied lodash-style set() helpers elsewhere in your codebase.
Code-level fixes
The defensive pattern is straightforward, even if it is annoying to retrofit:
- Reject dangerous path segments outright, including proto, constructor, and prototype.
- Prefer allowlisted structural updates over free-form dotted-path setters.
- Keep untrusted data as values, not as structural instructions.
- Use plain dictionaries with null prototypes where flexible maps are unavoidable.
const blocked = new Set(["__proto__", "constructor", "prototype"])
function assertSafePath(segments) {
for (const segment of segments) {
if (blocked.has(segment)) throw new Error("unsafe path")
}
}Runtime and platform controls
- Freeze or seal security-sensitive configuration objects after initialization where practical.
- Separate tracing and redaction workers from execution workers so polluted state cannot pivot into agent runtime.
- Minimize ambient authority for outbound HTTP, especially metadata endpoints and internal admin planes.
- Monitor for suspicious property names in telemetry, including constructor.prototype patterns.
Architectural Lessons
Why AI orchestration is a multiplier
Traditional web apps also suffer from prototype pollution, but orchestration frameworks amplify the blast radius:
- They normalize many heterogeneous payloads into one in-memory object model.
- They frequently use plugins, MCP connectors, retrievers, and tool adapters with loose schemas.
- They centralize logging, tracing, evaluation, and redaction in shared process space.
- They often treat metadata as low risk, even though metadata is exactly where structural bugs thrive.
That combination makes “harmless” utility flaws dangerous. A polluted property in a generic SDK can cross trust boundaries far beyond its original feature area.
What mature teams should change
- Threat-model tracing and observability code as production attack surface, not support code.
- Ban generic object-path mutation for untrusted input in code review standards.
- Audit gadget chains, not just single CVEs: HTTP clients, template engines, serializers, and policy checks are all potential second-stage sinks.
- Treat agent frameworks as integration platforms, because that is what attackers see.
The best takeaway from CVE-2026-40190 is not “upgrade one package and move on.” It is that AI engineering stacks have inherited the oldest JavaScript footguns while adding new cross-component pathways for exploitation. Prototype pollution remains one of the clearest examples of a bug class whose true severity depends less on the first write and more on everything your architecture allows that write to touch later.
Frequently Asked Questions
What is CVE-2026-40190 in the LangChain ecosystem? +
langsmith SDK before 0.5.18. The issue was tied to an incomplete guard in an internal lodash-style set() helper used by createAnonymizer().Why is prototype pollution dangerous in AI orchestration frameworks? +
Was the Python LangSmith SDK affected? +
Is the CVSS score enough to judge real risk here? +
How do I defend against constructor.prototype pollution bugs? +
__proto__. Reject constructor and prototype path segments too, avoid generic dotted-path setters for untrusted data, and isolate tracing or transformation code from execution-critical components.Get Engineering Deep-Dives in Your Inbox
Weekly breakdowns of architecture, security, and developer tooling — no fluff.