LangGrinch: How Nixer Detects CVE-2025-68664 CVE-2025-68664
The Vulnerability: What's Actually Broken
LangChain Core's dumps() and dumpd() functions serialize Python objects into a JSON-compatible string format for storage or transmission. These functions handle two types of data:
- Native LangChain objects — marked with a reserved
lckey, which tellsload()how to reconstruct the original object. - Free-form dictionaries — arbitrary user data that should be stored as-is, with no special treatment.
The bug: dumps() never escaped the lc key inside free-form dicts. So if a dict contained {"lc": 1, "type": "secret", "id": ["OPENAI_API_KEY"]}, it was serialized identically to a legitimate LangChain Secret object — and load() had no way to distinguish them.
The fix (commit 5ec0fa69) wraps free-form dicts that contain lc keys in a special marker class, preventing them from being misinterpreted as LangChain objects:
Why This Is Critical: The Attack Chain
LangChain agents are designed to pass data through serialization loops:
An attacker doesn't need to send malicious code directly. They send a prompt like:
If the agent stores LLM metadata via dumps(), the injected dict is silently rehydrated as a Secret object during the next load() call — even if no explicit deserialization is called by the application, because internal methods like astream_events(version="v1") and RunnableWithMessageHistory trigger serialization paths automatically.
The Secret class reads the named environment variable and resolves it at load time. The extracted secret then appears in the reconstructed object graph, readable by any downstream tool or log statement. This was the default behavior until the patch.
Why Generic CI/CD Scanners Miss This
Semgrep and CodeQL default rule sets are built for general-purpose languages and frameworks. Serialization injection in AI framework internals is outside their threat model.
Why Semgrep misses it
- Default Semgrep rules check for
pickle.load(),yaml.unsafe_load(), and known insecure deserialization patterns. - The vulnerable code in
langchain_core/load.pycalls a custom serializer that isn't in any rule set — it looks like benign utility code. - No hardcoded pickle or yaml in the call path to trigger alerts.
Why CodeQL misses it
- Stock security query packs detect known dangerous sinks (eval, exec, pickle, YAML) but not AI-stack-specific serialization APIs.
- The
dumps()function is a custom serializer — the taint analysis doesn't trace thelckey as a dangerous marker. - The vulnerability is in a dependency, not in the application code itself — SAST scanning the app repo won't flag it unless the vulnerable version is in
package.json/requirements.txt and the tool checks transitive deps.
Nixer's model-supply-chain module understands the lc serialization surface in LangChain: It detects calls to langchain_core.load functions (dumps, load, dumpd, loads) in code paths. It flags when user-controlled data (function arguments, LLM output fields, metadata) flows into these functions without sanitization. It cross-references the installed version of langchain-core against the CVE database.
How Nixer Detects CVE-2025-68664
Detection Rule Logic
| Rule ID | nixer/model-supply-chain/langchain-serialization-injection |
| Severity | CRITICAL |
| CVSS | 9.3 |
| Module | model-supply-chain |
Taint sources (user-controlled):
llm_response.metadatallm_response.additional_kwargsuser_input → function argumenttool return value → serialized state
Dangerous sinks:
langchain_core.load.dumps()langchain_core.load.dumpd()langchain_core.load.loads()withsecrets_from_env=Trueastream_events(version="v1")— internal serialization triggerRunnableWithMessageHistory— internal serialization trigger
Version check:
langchain-core < 0.3.81→ VULNERABLElangchain-core >= 1.2.5→ FIXED
Example Finding in Nixer's JSON Output
SARIF Output (GitHub Security Tab)
Remediation
Immediate (upgrade)
Safe deserialization pattern
CI/CD: fail the build on this rule
Audit your dependency tree
Related CVEs Found in Same Scan
| CVE | Package | CVSS | Description |
|---|---|---|---|
CVE-2025-68664 |
langchain-core | 9.3 | Serialization injection → secret leak |
CVE-2024-36480 |
langchain-core | 9.0 | eval() RCE via chat model output |
CVE-2023-46229 |
langchain | 7.5 | SSRF via sitemap loading |