PraisonAI: Crawl4AI/Chromium backend is also affected by the `web_crawl` SSRF validation bypass
Description
## Summary The DNS-rebinding / redirect SSRF bypass in PRAI-05 is **not limited to the httpx/urllib backend**. When `crawl4ai` (headless Chromium via Playwright) is installed, `web_crawl` auto-selects `provider=crawl4ai`, and the headless browser re-resolves DNS and follows redirects on its own — with no per-connection SSRF guard. Runtime-confirmed read-back of the internal canary via both DNS rebinding and redirect (`provider: "crawl4ai"`). Status: runtime-confirmed addendum to PRAI-05. ## Details ### Affected component - Package `praisonaiagents` 4.6.63. Backend selected when `crawl4ai`+Playwright are installed. - Files: `src/praisonai-agents/praisonaiagents/tools/web_crawl_tools.py` (`_crawl_with_crawl4ai`) and `src/praisonai-agents/praisonaiagents/tools/crawl4ai_tools.py` (standalone crawl wrappers). ### Vulnerable code / root cause Path: `src/praisonai-agents/praisonaiagents/tools/web_crawl_tools.py` Function: `_crawl_with_crawl4ai` Snippet: ```python async with AsyncWebCrawler() as crawler: for url in urls: result = await crawler.arun(url=url) # headless browser: re-resolves DNS, follows redirects ``` Path: `src/praisonai-agents/praisonaiagents/tools/crawl4ai_tools.py` Function: `Crawl4AITools.crawl` / `crawl4ai` Snippet: ```python result = await crawler.arun(url=url, config=config) # no _is_safe_crawl_url / no per-connect validation ``` Issue: the only SSRF check is the single pre-fetch `_is_safe_crawl_url()` on the initial URL string in `web_crawl()` (see PRAI-05). The headless browser then resolves and connects independently and follows redirects in-browser — no resolved-IP pinning, no per-hop/per-connect validation. Input (`urls`) is attacker/agent-controlled; the sink is `crawler.arun(url=...)`; the guard is bypassed by DNS rebinding (TOCTOU) and by redirects (followed in-browser). ### Attack flow / Why bypassed / Security boundary Identical to PRAI-05: TOCTOU between the guard's resolution and the browser's connection; redirects followed in-browser; internal response returned as crawl `content`. See PRAI-05. ## Proof of Concept ### Environment `crawl4ai` + Playwright Chromium installed in a dedicated runtime container (`127.0.0.1:18081`), same controlled internal canary + rebinding DNS. Runnable assets: `PraisonAI-Runtime-Repro\runtime-files\` (`docker-compose.crawl.yml`). ### Steps to reproduce 1. `SSRF-04-01-Crawl4AI-DNS-Rebind-Trigger` → `127.0.0.1:18081`: ```http POST /tool/web_crawl HTTP/1.1 Host: 127.0.0.1:18081 Content-Type: application/json {"url":"http://rebind.lab:8081/secret"} ``` 2. Redirect variant `SSRF-04-03-Crawl4AI-Redirect-Readback`: `{"url":"http://redirector:8082/redirect-to-internal"}`. ### Expected result The crawl backend refuses internal destinations regardless of DNS timing/redirects. ### Actual result HTTP 200, `"provider":"crawl4ai"`, response `content` contains `PRAISONAI_INTERNAL_SECRET_CANARY_7f3a91` + `FAKE_INTERNAL_TOKEN_DO_NOT_USE_7f3a91` for both the DNS-rebinding and the redirect payload. ### Screenshots **Crawl4AI DNS rebinding read-back** The attacker-controlled `rebind.lab` URL is accepted by the Crawl4AI-backed `web_crawl` endpoint. PraisonAI returns the internal canary response body containing `PRAISONAI_INTERNAL_SECRET_CANARY_7f3a91`. <img width="1542" height="763" alt="01-Crawl4AI-Burp-Readback" src="https://github.com/user-attachments/assets/a03b3a1c-e382-4f67-8ea6-b766dceb4a69" /> **Crawl4AI DNS rebinding runtime evidence** The runtime log shows the Crawl4AI/Chromium backend resolving `rebind.lab` to an internal Docker IP during the fetch phase. The internal canary receives `GET /secret` from a headless Chrome user agent. <img width="1659" height="946" alt="02-Crawl4AI-DNS-Log-And-Internal-Hit" src="https://github.com/user-attachments/assets/d93db090-3e39-43d0-af3b-5d1d8f614db8" /> **Crawl4AI redirect read-back** The attacker-controlled redirector URL is accepted by the Crawl4AI-backed endpoint. PraisonAI follows the redirect and returns the internal canary response body. <img width="1544" height="771" alt="03-Crawl4AI-Redirect-Readback" src="https://github.com/user-attachments/assets/7d05c8aa-5bda-45bc-b94c-bef0bdcf055c" /> **Crawl4AI redirect runtime evidence** The controlled redirector returns `302 -> http://internal-canary:8081/secret`, and the internal canary receives `GET /secret` from the Crawl4AI/Chromium backend. <img width="1590" height="920" alt="04-Crawl4AI-Redirect-Internal-Hit-Log" src="https://github.com/user-attachments/assets/dd9c0fec-3583-43ab-b83c-4470fa6aa409" /> ## Impact Same class as PRAI-05: read-back SSRF to internal/metadata services, now on the crawl4ai backend. Broadens the affected surface (the flaw is in the shared validate-without-pinning design, not one backend). ## Suggested remediation Resolve-once + IP-pin + per-connect validation must also cover the crawl4ai backend (constrain the headless browser to the validated IP, or allowlist crawl destinations).
CVSS v3.1 base metrics
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:NHigh severity
Band computed from the CVSS base score, not the source's own label — so it means the same thing across every feed.
AV
Network
Attack Vector
AC
Low
Attack Complexity
PR
Low
Privileges Required
UI
None
User Interaction
S
Changed
Scope
C
High
Confidentiality
I
Low
Integrity
A
None
Availability
Affected
- Vendor
- PyPI
- Product
- praisonaiagents
Versions
- pkg:pypi/praisonaiagents < 1.6.78
Stated as the source expressed them.
References
- advisoryOSV GHSA-6g59-gm2v-qhvqhttps://osv.dev/vulnerability/GHSA-6g59-gm2v-qhvq
- otherOSV webhttps://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-6g59-gm2v-qhvq
- advisoryOSV advisoryhttps://nvd.nist.gov/vuln/detail/CVE-2026-61429
- vendorOSV packagehttps://github.com/MervinPraison/PraisonAI
- otherOSV webhttps://www.vulncheck.com/advisories/praisonai-before-ssrf-via-crawl4ai-chromium-backend
Related threats
same CWE or vendorCVE-2026-107715 — The Mechanize library is used for automating interaction with websites.
CVE-2026-107715 · 1h ago
CVE-2026-107714 — The Mechanize library is used for automating interaction with websites.
CVE-2026-107714 · 1h ago
CVE-2026-107399 — The Mechanize library is used for automating interaction with websites.
CVE-2026-107399 · 1h ago
CVE-2026-107781 — Dromara Skyeye through commit 003549ae5615bd114ba5bb8ddf6a8e8ead97c321 contains a server-side request forgery and missing authorization vulnerabili…
CVE-2026-107781 · 2h ago
CVE-2026-84274 — IBM Guardium Data Protection 12.2.2 is affected by a sensitive information exposure vulnerability.
CVE-2026-84274 · 3h ago
CVE-2026-107394 — Indico is an event management system that uses Flask-Multipass, a multi-backend authentication system for Flask.
CVE-2026-107394 · 3h ago