Back to list
os.system(f'pip install {library}')
"os.system(f'pip install {library}')"
Translated: 2026/4/25 0:01:08
Original Content
Update: This was found in an older version of CrewAI's code interpreter. CrewAI has since removed the tool entirely. The finding is real but historical. The point is the class of problem, not the specific instance.
I've been building a static effect analyzer. You point it at a Python or TypeScript file and it tells you what each function does to the outside world: network, filesystem, database, subprocess, etc.
I ran it on CrewAI's code interpreter and got this:
$ libgaze check code_interpreter.py
run_code_unsafe:347 can Unsafe
365 | os.system(f"pip install {library}")
370 | exec(code, {}, exec_locals)
2/13 functions are pure.
Line 365. library is a string from the LLM. No validation, no allowlist. The LLM decides what gets pip-installed on your machine via os.system with an f-string.
The function is honestly named run_code_unsafe. But the function that calls it, _run, is 150 lines long and picks between the "safe" and "unsafe" paths based on a config flag. The tool traces the call graph and shows that _run inherits Unsafe:
_run:194 can Fs, Net, Unsafe
If A calls B and B is Unsafe, A is Unsafe. You can't hide it behind indirection.
There are ten effects. Fixed list, not extensible:
Net Fs Db Console Env Time Rand Async Unsafe Fail
The analyzer does two passes. First, walk the AST and check every call against a table of known effects (os.system is Unsafe, requests.get is Net, open() is Fs, etc.). Second, propagate through the call graph within the file. Iterate until stable.
No type inference. No cross-file analysis. Just the AST and a vocabulary. It's enough to find the CrewAI thing and a lot of things like it.
I scanned 15,293 functions across CrewAI, LangChain, AutoGPT, MCP Servers, Vercel AI SDK, and OpenAI Agents JS. The same ten effects worked for all of them. Didn't add or remove a single one between Python and TypeScript.
pip install libgaze
libgaze check your_file.py
npm install -g libgaze-ts
libgaze-ts check your_file.ts
Zero dependencies on the Python side. 2.4MB on the TypeScript side (oxc-parser, not the full TypeScript compiler).
Both support --json, directory scanning, --deny for CI gating, and .gazepolicy files for per-function rules. There's a GitHub Action too.
The repo is github.com/itchymutt/gaze. MIT licensed.
If you run it on something and find something interesting, let me know.