medium

CVE-2026-55535

PyPI · PraisonAI

Summary

PraisonAI vulnerable to Server-Side Request Forgery via DNS rebinding bypass in webhook_url validation

Severity
medium
CVSS
6.8
EPSS
0.3% (p28)
CWE
CWE-367, CWE-918
Also known as
GHSA-hmfx-4v44-9qw9
Published
2026-08-25
Updated
2026-08-25

Advisory details

Summary

The webhook_url field in the Jobs API silently passes validation when DNS resolution fails (socket.gaierror), enabling DNS rebinding attacks. An attacker's domain can initially resolve to a public IP (passing validation) then switch to an internal IP before the server makes the HTTP request.

Details

The validator catches socket.gaierror and silently allows the URL:

# src/praisonai/praisonai/jobs/models.py:55
try:
    ip = socket.gethostbyname(hostname)
    ip_obj = ipaddress.ip_address(ip)
    if ip_obj.is_private or ip_obj.is_loopback:
        raise ValueError("private address")
except socket.gaierror:
    pass  # BUG: DNS failure silently ignored → SSRF bypass

The HTTP call is made later with no re-validation:

# src/praisonai/praisonai/jobs/executor.py:402
async with httpx.AsyncClient() as client:
    await client.post(job.webhook_url, ...)  # no second IP check

Proof of Concept

DNS rebinding flow:

  1. Register attacker.com with TTL=1s → resolves to 1.2.3.4 (public IP)
  2. Submit job: webhook_url=http://attacker.com/callback
  3. Validation passes (public IP)
  4. Switch DNS: attacker.com → 127.0.0.1
  5. Job completes → server POSTs to 127.0.0.1 → internal SSRF

Unresolvable domain bypass (no DNS rebinding required):

curl -X POST http://:8005/api/v1/runs \
  -d '{"prompt":"run","webhook_url":"http://unresolvable.internal/cb","agent_yaml":"..."}'
# Validation: gaierror → pass → URL accepted

Impact

SSRF to internal HTTP services: admin panels, databases, and cloud metadata APIs (e.g., http://169.254.169.254/). Exploitable without authentication.

References

Related advisories

Is your project exposed to this? Stateward checks every dependency on every pull request and flags it only if your code actually reaches it.

Check my repo

Summarize with AI

ChatGPTClaudePerplexity

Sources: CISA KEV (public domain), OSV.dev & GitHub Advisory Database (CC-BY-4.0), FIRST EPSS, NVD/CWE (public domain). Served live from the Stateward advisory database.