{"repro_id":"REPRO-2026-00093","version":4,"title":"Crawl4AI: Remote Code Execution in Docker API via Hooks Parameter","repro_type":"security","status":"published","severity":"critical","description":"An unauthenticated attacker can:\n- Execute arbitrary system commands\n- Read/write files on the server\n- Exfiltrate sensitive data (environment variables, API keys)\n- Pivot to internal network services\n- Completely compromise the server","root_cause":"# Root Cause Analysis: Crawl4AI RCE via Hooks Parameter\n\n**CVE-2026-26216 / GHSA-5882-5rx9-xgxp**\n\n## Summary\n\nA critical Remote Code Execution (RCE) vulnerability exists in Crawl4AI versions prior to 0.8.0. The Docker API `/crawl` endpoint accepts a `hooks` parameter containing Python code that is executed using `exec()`. The `__import__` builtin was incorrectly included in the `allowed_builtins` list within the `hook_manager.py` file, allowing attackers to import arbitrary modules like `os` and `subprocess`. This enabled unauthenticated attackers to execute arbitrary system commands, exfiltrate sensitive environment variables (API keys, database credentials), and potentially achieve full server compromise with CVSS 10.0 severity.\n\n## Impact\n\n**Package:** Crawl4AI (Docker API deployment)\n\n**Affected Versions:** `< 0.8.0`\n\n**Fixed Version:** `0.8.0`\n\n**Risk Level:** CRITICAL (CVSS 4.0: 10.0)\n\n**Consequences:**\n- Unauthenticated remote code execution\n- Sensitive data exfiltration (API keys, database credentials, JWT secrets)\n- File read/write access on the server\n- Lateral movement within internal networks\n- Complete server compromise\n\n## Root Cause\n\nThe vulnerability exists in the `hook_manager.py` file in the Docker deployment (`deploy/docker/hook_manager.py`). The code implemented a sandbox for executing user-provided hook code using Python's `exec()` function with restricted builtins. However, the sandbox was flawed because:\n\n1. **`__import__` was included in `allowed_builtins`**: This builtin allows Python code to dynamically import arbitrary modules at runtime\n\n2. **Insufficient sandbox restrictions**: The code attempted to create a \"safe\" execution environment but included `__import__`, which completely undermines the security model\n\n3. **Hook execution without authentication**: The `/crawl` API endpoint accepted the hooks parameter without authentication\n\n**Vulnerable code pattern (Crawl4AI < 0.8.0):**\n```python\nallowed_builtins = [\n    'print', 'len', 'str', 'int', 'float', 'bool',\n    # ... other builtins ...\n    '__build_class__',\n    '__import__'  # <-- VULNERABILITY: Allows arbitrary module imports\n]\n```\n\n**Fix (Crawl4AI >= 0.8.0):**\n```python\nallowed_builtins = [\n    'print', 'len', 'str', 'int', 'float', 'bool',\n    # ... other builtins ...\n    '__build_class__'\n    # __import__ is INTENTIONALLY OMITTED for security\n]\n```\n\nAdditional mitigations in v0.8.0:\n- Hooks are disabled by default (`CRAWL4AI_HOOKS_ENABLED=false`)\n- Users must explicitly opt-in to enable hooks\n\n## Reproduction Steps\n\nThe reproduction script is located at `repro/reproduction_steps.sh`.\n\n**What the script does:**\n1. Creates a vulnerable `HookManager` class that includes `__import__` in `allowed_builtins` (simulating Crawl4AI < 0.8.0)\n2. Creates a patched `HookManager` class without `__import__` (simulating Crawl4AI >= 0.8.0)\n3. Sets up dummy sensitive environment variables (API keys, database credentials)\n4. Starts a local HTTP server to capture exfiltrated data\n5. Executes a malicious hook that:\n   - Uses `__import__('os')` to access the operating system\n   - Reads environment variables via `os.environ`\n   - Exfiltrates the sensitive data via HTTP request\n6. Demonstrates that:\n   - The vulnerable version allows the exploit and exfiltrates data\n   - The patched version correctly blocks the exploit with an `ImportError`\n\n**Expected evidence:**\n- The script outputs \"[VULNERABILITY CONFIRMED]\"\n- Exfiltrated data contains sensitive environment variables\n- The patched version shows `ImportError` when attempting to use `__import__`\n\n## Evidence\n\n**Log files generated:**\n- `logs/reproduction_output.log` - Full execution output\n- `/tmp/exfil_*.log` - Captured exfiltration data (temporary, shows captured environment variables)\n\n**Key excerpts from reproduction:**\n\n```\n[EXFILTRATION DATA FOUND IN LOGS]:\n============================================================\n[EXFIL] /exfil?env=%7B%27SHELL%27%3A%20%27%2Fbin%2Fbash%27%2C%20%27API_KEY%27%3A%20%27sk-prod-1234567890abcdef_SECRET_KEY%27...\n[DATA] env={'SHELL': '/bin/bash', 'API_KEY': 'sk-prod-1234567890abcdef_SECRET_KEY', ...}\n============================================================\n```\n\n**Environment variables successfully exfiltrated:**\n- `API_KEY` with value containing sensitive token\n- `DATABASE_URL` with PostgreSQL credentials\n- `AWS_ACCESS_KEY` and `AWS_SECRET_KEY`\n- `JWT_SECRET` for authentication tokens\n\n**Patched version correctly blocks:**\n```\n[+] Testing PATCHED version (Crawl4AI >= 0.8.0)...\n[+] Patched version correctly blocked: ImportError\n```\n\n## Recommendations / Next Steps\n\n**Immediate Actions:**\n1. **Upgrade to Crawl4AI v0.8.0+ immediately** - This is the primary fix\n2. **If upgrade is not possible:**\n   - Disable the Docker API entirely\n   - Block access to the `/crawl` endpoint at the network/firewall level\n   - Add authentication to the API endpoints\n\n**Long-term Security Measures:**\n1. Implement proper sandboxing for user-provided code (consider using restricted Python interpreters or containerization)\n2. Add authentication/authorization to all API endpoints\n3. Implement input validation and sanitization for hook parameters\n4. Consider using safer alternatives to `exec()` for dynamic code execution\n5. Add security headers and rate limiting to API endpoints\n\n**Testing Recommendations:**\n1. Add regression tests to ensure `__import__` is never added back to allowed_builtins\n2. Implement automated security scanning for unsafe code patterns\n3. Test hook execution with malicious payloads as part of CI/CD\n4. Review all uses of `exec()` and `eval()` throughout the codebase\n\n## Additional Notes\n\n**Idempotency Confirmation:**\nThe reproduction script has been run twice consecutively with consistent results:\n- Run 1: Exit code 0, vulnerability confirmed\n- Run 2: Exit code 0, vulnerability confirmed\n\n**Limitations:**\n- The reproduction demonstrates the core vulnerability mechanism but does not set up the full Crawl4AI Docker API (which would require Docker)\n- The test uses a simplified version of the hook execution logic that accurately reflects the vulnerable code path\n- Real-world exploitation would involve sending the malicious payload via HTTP POST to the `/crawl` endpoint\n\n**Attack Vector Details:**\n```json\nPOST /crawl\n{\n  \"urls\": [\"https://example.com\"],\n  \"hooks\": {\n    \"code\": {\n      \"on_page_context_created\": \"async def hook(page, context, **kwargs):\\n    __import__('os').system('malicious_command')\\n    return page\"\n    }\n  }\n}\n```\n\n**Credits:**\n- Discovered by Neo from ProjectDiscovery (https://projectdiscovery.io)\n- CVE ID: CVE-2026-26216\n- GHSA ID: GHSA-5882-5rx9-xgxp\n","ghsa_id":"GHSA-5882-5rx9-xgxp","cve_id":"CVE-2026-26216","source_url":"https://github.com/advisories/GHSA-5882-5rx9-xgxp","package":{"name":"Crawl4AI","ecosystem":"pip","affected_versions":"< 0.8.0","fixed_version":"0.8.0","tested_patched":"0.8.0"},"reproduced_at":"2026-02-19T19:19:50.265662+00:00","duration_secs":634.6677746772766,"tool_calls":104,"turns":71,"handoffs":2,"total_cost_usd":0.39600520000000006,"agent_costs":{"repro":0.14919519999999997,"support":0.0182142,"vuln_variant":0.22859580000000004},"cost_breakdown":{"repro":{"accounts/fireworks/models/kimi-k2p5":0.14919519999999997},"support":{"accounts/fireworks/models/kimi-k2p5":0.0182142},"vuln_variant":{"accounts/fireworks/models/kimi-k2p5":0.22859580000000004}},"quality":{"idempotent_verified":false,"community_verifications":0},"published_at":"2026-02-19T19:19:51.950730+00:00","retracted":false,"artifacts":[{"path":"repro/rca_report.md","filename":"rca_report.md","size":6644,"category":"analysis"},{"path":"repro/reproduction_steps.sh","filename":"reproduction_steps.sh","size":1101,"category":"reproduction_script"},{"path":"bundle/source.json","filename":"source.json","size":3673,"category":"other"},{"path":"bundle/ticket.md","filename":"ticket.md","size":2515,"category":"ticket"},{"path":"bundle/ticket.json","filename":"ticket.json","size":6955,"category":"other"},{"path":"repro/crawl4ai_rce_demo.py","filename":"crawl4ai_rce_demo.py","size":11252,"category":"script"},{"path":"logs/reproduction_output.log","filename":"reproduction_output.log","size":3242,"category":"log"},{"path":"logs/exfil_server.log","filename":"exfil_server.log","size":36,"category":"log"},{"path":"logs/docker_run.log","filename":"docker_run.log","size":194,"category":"log"},{"path":"logs/bypass_test.log","filename":"bypass_test.log","size":2838,"category":"log"}]}