high · 7.1CVE-2026-55537Aug 25, 2026

CVE-2026-55537: PraisonAI Webhook SSRF via DNS Fail-Open and TOCTOU Race

Rohit Hatagale
AI Security Researcher, SecureLayer7

PraisonAI's job webhook validator silently accepts URLs when DNS resolution fails, and re-resolves hostnames at execution time, letting an attacker redirect the server's HTTP POST to any internal…

PackagePraisonAI
Ecosystempip
Affected< 4.6.58
Fixed in4.6.58
CVE-2026-55537: PraisonAI Webhook SSRF via DNS Fail-Open and TOCTOU Race

The problem

The validate_webhook_url() method in jobs/models.py catches socket.gaierror with a bare pass, so any hostname that returns NXDOMAIN or times out during submission is accepted without restriction.

Even when DNS succeeds at validation time, JobExecutor._send_webhook() calls httpx.AsyncClient().post(job.webhook_url) minutes or hours later, performing a completely fresh DNS lookup. The gap between these two resolutions is a classic TOCTOU window that enables DNS rebinding to internal addresses.

Proof of concept

A working proof-of-concept for CVE-2026-55537 in PraisonAI, with the exact payload below.

bash
# 1. Submit job while rebind.attacker.com returns NXDOMAIN (DNS fail-open bypasses validator)
curl -X POST http://praisonai-server:8000/jobs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Calculate 2+2",
    "webhook_url": "http://rebind.attacker.com/callback"
  }'
# Response: {"job_id": "job_abc123", "status": "queued"}

# 2. Add DNS A record: rebind.attacker.com -> 127.0.0.1 (TTL=60)

# 3. Wait for job to complete. _send_webhook() resolves rebind.attacker.com -> 127.0.0.1
#    POST /callback reaches 127.0.0.1 (SSRF)

The root cause is two cooperating flaws. First, the except socket.gaierror: pass block in validate_webhook_url() (CWE-703 / fail-open) means any NXDOMAIN or transient DNS error at submission time causes the validator to return the URL unchanged. Second, httpx.AsyncClient creates a new TCP connection on every call with no shared DNS cache from the validator, so hostname resolution at execution time is entirely independent (CWE-367 TOCTOU).

The patch fixes the first flaw by replacing pass with raise ValueError(...), making the validator fail-closed on DNS errors, and adds a re-validation step inside _send_webhook() before the HTTP call to close the TOCTOU window.

The fix

Upgrade praisonai to version 4.6.58 or later. The fix changes the except socket.gaierror: pass handler to raise a ValueError, rejecting any webhook URL whose hostname cannot be resolved at submission time. It also adds a pre-flight DNS check inside _send_webhook() so a URL that passes submission-time validation is re-validated at execution time, blocking DNS rebinding attacks.

Reporter not attributed.

References: [1][2][3][4]

Related research