system: OPERATIONAL
← back to all hacks
INFRASTRUCTURE MEDIUM NEW

LangChain Core path traversal: legacy load_prompt reads arbitrary files

CVE-2026-34070 lets crafted prompt configs walk LangChain's filesystem via load_prompt, exposing .txt/.json/.yaml secrets. Disclosed March 27, 2026, fixed in langchain-core 1.2.22.

2026-06-19 // 6 min affects: langchain-core, langchain, llm-orchestration-frameworks

What is this?

CVE-2026-34070 is a path traversal vulnerability in langchain-core, the foundational package of the widely used LangChain LLM-orchestration framework. It was disclosed on March 27, 2026 by researchers at Cyera as part of their “LangDrained” analysis, and assigned advisory GHSA-qh6h-p6c9-ff54. The flaw sits in a set of undocumented legacy prompt-loading APIs: load_prompt(), load_prompt_from_config(), and the .save() method on prompt classes, all in langchain_core.prompts.loading.

The classification is mundane — CWE-22, “Improper Limitation of a Pathname to a Restricted Directory” — and that is precisely the point. The bug is not an exotic AI attack. It is a classic, decades-old web vulnerability that resurfaced inside the plumbing of an AI framework, where it can be reached through prompt configuration data rather than a URL. NVD rates it CVSS 3.1 7.5 (High); Snyk’s CVSS 4.0 assessment puts it at 8.7.

How it works

The vulnerable functions read files from paths embedded in deserialized configuration dictionaries. When an application loads a prompt from a config object, those functions resolve a file path and read its contents — without validating the path against directory traversal sequences or absolute-path injection.

If an application passes user-influenced prompt configuration to load_prompt() or load_prompt_from_config(), an attacker who controls that configuration can supply a path containing ../ sequences (or an absolute path) and read arbitrary files from the host filesystem. The only constraint is a file-extension check: templates are read as .txt, and example files as .json or .yaml. Within those extensions, nothing stops a request from walking out of the intended prompt directory toward configuration files, environment exports, or credential stores that happen to use a permitted extension.

# Illustrative shape of the dangerous pattern — do NOT load untrusted prompt configs
from langchain_core.prompts import load_prompt

# 'config' is attacker-influenced (e.g. uploaded, fetched, or templated)
config = {
    "_type": "prompt",
    "template_path": "../../../../[REDACTED_SENSITIVE_PATH].yaml",
}
prompt = load_prompt(config)   # reads the traversed file, constrained only by extension

The exploitation precondition is the key nuance: the danger is realized only when an application feeds untrusted configuration into these legacy loaders. The impact is information disclosure (confidentiality), not write access or code execution — the CVSS vector records high confidentiality impact with no integrity or availability impact.

Why it matters

This is the third item in a pattern Cyera highlighted across LangChain and LangGraph: input-validation failures in the “invisible, foundational plumbing” that connects models to business workflows. They analysed CVE-2026-34070 alongside an earlier unsafe-deserialization flaw in langchain-core (CVE-2025-68664, rated 9.3, December 2025) and an SQL injection in LangGraph’s checkpointer (CVE-2025-67644, 7.3). Each maps to a different layer and a different class of data — local files, runtime secrets, stored agent state.

The broader lesson is that AI orchestration frameworks inherit the entire attack surface of ordinary software, plus new entry points. A path traversal that once required a malicious HTTP parameter can now ride in on a prompt template fetched from a repository, a user-supplied agent configuration, or a serialized object pulled from a database. The same theme runs through LiteLLM’s pre-auth SQLi, the LangFlow path traversal, and the pgAdmin LLM-API flaw: traditional bugs sitting unusually close to credentials and model traffic, in code that did not exist three years ago.

Defenses

The first and most concrete step is to upgrade: langchain-core 1.2.22 fixes the issue, with a backport in the 0.3.x line at 0.3.86. All versions before those are affected.

Beyond patching, the maintainers’ own remediation points the way. The legacy load_prompt family is now formally deprecated and slated for removal in 3.0.0-era releases; it is superseded by the dumpd / dumps / load / loads serialization APIs in langchain_core.load, which do not perform filesystem reads and use an allowlist-based security model. Migrating off the legacy loaders removes the dangerous primitive entirely rather than trying to sanitise around it.

For application teams that cannot migrate immediately, treat prompt configuration as untrusted input. Never pass user-, network-, or repository-sourced config dictionaries to load_prompt() or load_prompt_from_config() without validation. Enforce an allowlist of permitted prompt directories, resolve and canonicalise any path before use, and reject absolute paths and .. components. As Cyera notes, the guidance here is simply established secure-coding practice applied to AI pipelines: validate paths, restrict directory boundaries, avoid unsafe deserialization, and prefer parameterised, allowlist-driven interfaces over ones that interpret raw attacker-influenced strings.

Status

ItemValue
CVECVE-2026-34070 (GHSA-qh6h-p6c9-ff54)
Affectedlangchain-core, all versions before 1.2.22 (0.3.x before 0.3.86)
Fixed inlangchain-core 1.2.22 (backport 0.3.86)
WeaknessCWE-22 Path Traversal
SeverityCVSS 3.1 7.5 (NVD) / CVSS 4.0 8.7 (Snyk)
ImpactArbitrary file read (.txt/.json/.yaml), confidentiality only
DisclosedMarch 27, 2026 (Cyera “LangDrained”)
StatusPatched; legacy APIs deprecated for removal

The fix is shipped and the affected APIs were undocumented legacy interfaces, so the practical exposure is limited to applications that still call them on untrusted configuration. Audit your codebase for load_prompt, load_prompt_from_config, and prompt .save() calls, confirm your langchain-core version, and plan the migration to langchain_core.load.

Sources