High

Unsafe Pickle Serialization in Sandbox Tool Result Transport

Older versions of the Letta agent framework sent tool results between the sandbox and server using Python's pickle format instead of JSON. Because pickle can execute arbitrary code when loaded, an attacker who can influence a tool result can smuggle in a malicious payload that runs as soon as the server deserializes it.

How the attack works

An agent's sandboxed tool produces a result that is serialized with pickle.dumps before being sent back to the server. If an attacker controls or can tamper with that result — for example by compromising a tool, a dependency, or the data it returns — they can insert a crafted object with a __reduce__ method or a base64-wrapped pickle stream. When the server calls pickle.loads to read the result, that crafted object runs its embedded code immediately. This detection watches for a monitored agent spawning a Python process whose command line shows this pickle dump/load transport pattern, which is the exact mechanism used before Letta 0.16.8 fixed the issue by switching to JSON.

Netzilo detection

Netzilo reports this behaviour when it is observed.

Signature ID
b7f3c1d2-9a4e-4f61-8c25-3d0e6a7b1f48
Severity
High

Why it matters

Successful exploitation gives an attacker arbitrary code execution on the server process handling the agent's sandbox, which can lead to full compromise of the agent runtime and anything it has access to.

What you can do

  • Upgrade Letta to 0.16.8 or later, where tool results are transported as JSON instead of pickle.
  • Audit any custom sandbox wrappers or tool integrations for direct use of pickle.dumps/pickle.loads on data that crosses a trust boundary.
  • Treat any tool result content as untrusted input and validate or restrict what tools can return before it reaches deserialization code.
  • If you see this pattern outside of known safe uses like torch.load, joblib.load, pandas.read_pickle, code audits, or test suites, investigate whether it is an unpatched deployment or an active injection attempt.

Known benign look-alikes

  • Data-science and ML one-liners that legitimately pickle/unpickle a local cache or feature artifact via `python -c` (e.g. cache warmers, notebook export scripts). Not filtered by name because the pattern is indistinguishable from the vulnerable transport; torch.load, joblib.load and pandas.read_pickle are excluded from the match list precisely to keep the common ML paths quiet.
  • Engineers auditing Letta or another codebase for pickle usage with grep/rg/git grep (suppressed by filter_readonly_inspect).
  • Letta's own test suite and packaged fixtures exercising the legacy pickle path (suppressed by filter_test_harness).
  • Bandit / Semgrep / CodeQL runs that echo `pickle.loads(` from a rule pattern into a command line (suppressed by filter_security_tooling).
  • Remediation work during the 0.16.8 upgrade — one-off scripts converting pickled caches to JSON will report. This is expected and desirable during the patch window.
  • A legitimate base64 blob whose first characters coincide with a pickle opcode prefix. Requires 20+ contiguous base64 characters AND an interpreter/Letta context to fire.

References

Related threats