LangChain load_prompt Deserialization Code Execution
This detects a two-step pattern tied to an old LangChain vulnerability (CVE-2023-36281): a Python process reads a prompt, chain, or agent configuration file, and shortly after, that same process launches a shell command, network tool, or Python one-liner. That sequence is what code execution via a poisoned prompt/chain file looks like from the outside.
How the attack works
An attacker crafts a malicious prompt or chain specification file (JSON or YAML) whose template content abuses LangChain's `load_prompt`/`load_chain` deserialization to reach Python internals like `__subclasses__` or `__globals__`. When the application loads this file, the template is evaluated and arbitrary code runs inside the interpreter. The rule cannot see the deserialization itself; instead it watches for the outer signature: a Python process opens a file whose path looks like a prompt/template/chain/agent artifact, and within 5 minutes the same process (or a child it spawned) starts a shell, network utility, encoder, or `python -c` command. The two events are tied together by session and process lineage, not just by timing.
Netzilo detection
Netzilo reports this behaviour when it is observed.
- Signature ID
- 7f3c1a2e-9b4d-4f61-8c2a-5d0e6b7a1c93
- Severity
- High
- CVEs
- CVE-2023-36281
Why it matters
If exploited, an attacker gets arbitrary code execution inside the application's Python process, which can lead to data theft, lateral movement, or full host compromise via a single malicious prompt or chain file - a supply-chain-style entry point since the file itself is the attack payload.
What you can do
- →Upgrade LangChain past the version affected by CVE-2023-36281 and avoid loading prompt/chain files from untrusted or user-supplied sources.
- →Treat prompt/chain JSON and YAML files as executable content: validate their origin, restrict write access, and avoid dynamic template evaluation on untrusted input.
- →Review any case where a Python agent process reads a prompt/template/chain file and then spawns a shell or network command shortly after, since this is the exact observable behavior.
- →Be aware this pattern also occurs in legitimate agent frameworks (shell tools, CI test fixtures, notebooks that pip install after loading prompts) - confirm intent before treating a match as an incident.
Known benign look-alikes
- A LangChain / LlamaIndex application that legitimately loads a prompt or chain JSON from disk and then, in the same session, uses a Bash/Terminal tool - agent frameworks routinely spawn `sh -c` for their shell tool.
- CI and pytest runs that read prompt fixtures (`tests/**/prompt*.json`) and then invoke shell helpers, `chmod +x`, or `curl` for artifact upload.
- Notebook / Streamlit / Chainlit dev loops where the kernel reads a `*_prompt.json` and the same kernel later shells out for `pip install`.
- Non-LangChain configuration files that happen to carry a `agent`, `chain` or `template` token in the filename (e.g. `agent.json` for an unrelated service) read by a python process that later runs `curl`.
- Deployment scripts that render a Jinja/`template.yaml` and then run a packaging shell command.