LangChain PALChain exec() Sink Reached OS
Some LangChain applications ask an AI model to write a small program and then run that program directly with Python's exec(). If an attacker can influence the text the model sees, they can get the model to produce malicious code that the application then executes as if it were trusted. This detection watches for that exact pattern happening on the same process.
How the attack works
An attacker crafts input that steers the LLM into generating code containing a command it shouldn't run — a reverse shell, a download-and-execute command, base64-encoded payload, or similar. The vulnerable PALChain component asks the LLM to 'write a program' (an LLM request), then hands the model's output straight to Python's exec() or a subprocess call. The detection links these two steps — the LLM call and the suspicious command spawn — when they happen on the same interpreter process within a five-minute window. If the exec'd code then reaches out to the network, reads credential files, or spawns further processes, those are logged too as extra context, though they aren't required to trigger the detection.
Netzilo detection
Netzilo reports this behaviour when it is observed.
- Signature ID
- 6f3b1d0e-2a47-4c9e-9d1b-8e5f7a4c2b91
- Severity
- High
Why it matters
A successful attack gives the attacker arbitrary code execution on the server running the LangChain agent, which can lead to data theft, credential exposure, or a foothold for further compromise — all through an application that was only supposed to answer questions.
What you can do
- →Avoid using PALChain or similar 'LLM writes code, we exec() it' components in production; if you must, run them in a sandboxed, network-isolated process.
- →Never let untrusted or user-supplied text reach a prompt that feeds into code generation-and-execution chains.
- →Review any alert generated by this pattern for the specific command line executed — legitimate shell tools (ShellTool, BashTool, notebook cells) can produce the same LLM-then-shell-command sequence, so check intent before acting.
- →Restrict outbound network access and credential file permissions for processes that run LLM-driven code, so that even if exec() is abused, the damage is contained.
Known benign look-alikes
- Agentic frameworks that legitimately expose a shell tool (LangChain ShellTool, BashTool, terminal plugins). The interpreter makes an LLM call and then spawns 'sh -c <command>' as designed - the ordered chain looks identical. The report carries the full command line so an analyst can confirm intent.
- Notebook sessions (jupyter/ipython) where a developer runs an LLM cell and then a '!curl' / '!pip' shell-bang cell within the same 5 minute window.
- LangServe / uvicorn / gunicorn workers that call an LLM and also invoke ffmpeg, git, pandoc or similar via subprocess with an inline shell wrapper.
- Python LLM apps that use boto3 or kubectl helpers, which read ~/.aws/credentials or ~/.kube/config - this only adds an optional escalation stage, it cannot fire the rule on its own.
- Legitimate agent egress (package installs, model downloads) attributed to the spawned child, again only as an optional escalation stage.