High

PALChain Arbitrary Code Execution (LangChain)

Older versions of LangChain's PALChain feature take text generated by an AI model and run it directly with Python's exec(). If an attacker can influence what the model outputs, they can get arbitrary code to run on the machine hosting the agent.

How the attack works

An application uses LangChain's PALChain, which asks an LLM to produce a small Python program to solve a reasoning task. Instead of sandboxing that output, PALChain feeds it straight into Python's exec(). An attacker who can steer the model's output — via prompt injection or a poisoned input — writes code containing things like os.system, subprocess calls, socket connections, or base64-decoded payloads, and that code runs with the privileges of the agent process. The result looks like a Python interpreter spawning a shell, a reverse shell connection, or a download-and-execute sequence, all traceable back to the same agent session.

Netzilo detection

Netzilo reports this behaviour when it is observed.

Signature ID
b7e4c1f2-9a3d-4e58-8c61-3f0a2d5b7e94
Severity
High

Why it matters

An attacker who controls LLM output gets arbitrary code execution on the host running the agent, which can lead to data theft, lateral movement, or full compromise of the machine.

What you can do

  • Upgrade LangChain past version 0.0.199, or stop using PALChain's exec-based execution path entirely.
  • Never pass LLM-generated code to exec()/eval() without a strict sandbox (no filesystem, network, or subprocess access).
  • Run any agent components that execute generated code in an isolated, network-restricted environment with minimal privileges.
  • Monitor for Python processes spawning shells, network tools, or reverse-shell patterns shortly after an LLM-generation step in your agent pipeline.

Known benign look-alikes

  • pip / setuptools legacy build shim: `python -c 'import sys, setuptools, tokenize; ... exec(compile(...))'`. It carries a dynamic-exec primitive but no dangerous capability marker (no os.system / subprocess / socket / network tool), so anchor A does not fire.
  • Developer or notebook one-liners such as `python -c 'import subprocess; subprocess.run(["ls"])'` — capability marker present but no dynamic-exec primitive, so anchor A does not fire.
  • Security research, CVE-2023-36258 reproduction harnesses and red-team test suites deliberately running PAL payloads. These are genuine true positives of the pattern; the rule is report-only so the exercise is not interrupted, and the kill chain names the operator's own lineage.
  • Provisioning tooling (Ansible/Fabric-style bootstraps) that base64-decodes and execs a Python payload on the local host. Reported, not blocked; the emitted lineage makes the automation parent obvious to the analyst.
  • Container/CI entrypoints that legitimately pipe a fetched installer into a shell. Anchor B additionally requires a Python interpreter in the same session lineage, which excludes plain shell CI steps; when a Python build driver is present the event is reported for review only.

References

Related threats