FAISS Pickle Deserialization RCE - Python Host Spawns Payload Process
LangChain applications that load FAISS vector-store files using deserialize_from_bytes or load_local can be tricked into running attacker-controlled code, because the underlying pickle format lets a crafted file execute arbitrary commands when loaded. This rule watches for the moment that hidden code actually spawns a process on the machine, which is the visible sign the attack succeeded.
How the attack works
An attacker crafts a FAISS index file (or similar pickle blob) containing a malicious object whose __reduce__ method calls os.system or an equivalent. The victim application loads this file through LangChain's vector-store loading functions, and the pickle deserializer executes the embedded code inside the Python process. That code then spawns a child process - a reverse shell, a download-and-run command, an encoded exec, or similar - which is the only externally observable trace of the compromise. The rule confirms the chain by tracing the exact process lineage: it finds the specific Python (or python-hosted app server) instance that acted as the caller, checks that a suspicious child process appeared within a few hops downwind of it, and looks at sibling processes launched by the same interpreter instance within a five-minute window.
Netzilo detection
Netzilo reports this behaviour when it is observed.
- Signature ID
- b7c41f9e-2a83-4d16-9f0c-5e8a13d47c62
- Severity
- High
Why it matters
A successful exploit gives an attacker code execution inside whatever service loads the malicious vector store, which can lead to data theft, lateral movement, or further payload delivery - all from what looks like a normal file-load operation.
What you can do
- →Never load FAISS/vector-store files (or any pickle-based artifact) from untrusted or unauthenticated sources; treat them like executable code.
- →If your pipeline must load third-party or user-supplied vector stores, switch to a safe serialization format instead of pickle, or run the loading step in a sandboxed, network-isolated process.
- →Review any LangChain agents that have ShellTool/BashProcess enabled - this is a real capability, not a bug, so confirm it's an intentional design decision and restrict what commands it can run.
- →When investigating an alert, check the full process lineage back to the interpreter that spawned it and the command line of that interpreter, to separate legitimate MLOps tooling (dvc, aws, gcloud) from an actual payload.
Known benign look-alikes
- MLOps and data-pipeline code that legitimately shells out from Python (dvc, aws, gcloud, ffmpeg wrappers). Mitigated by requiring a payload-shaped command line - a plain "sh -c aws s3 cp ..." matches none of the HIGH or MED classes.
- LangChain agents deliberately equipped with ShellTool / BashProcess. These are a genuine policy decision and will be reported (never blocked) for review.
- Jupyter or IDE kernels running "!curl ... | sh" style shell magics from a notebook cell. The interpreter is the same, so the rule reports; triage on the lineage root.
- Build and install steps executed from Python (pip / setup.py) that run "chmod +x && ./configure". Medium class only - suppressed unless the interpreter command line also carries a langchain/faiss/pickle marker or a second payload-shaped child appears in the same 5-minute window.
- Deliberate CVE reproduction or red-team validation of the pickle PoC.