High

PraisonAI: Jobs API is unauthenticated by default and allows attacker-controlled webhook SSRF

  • Disclosed: 08.10.2026
  • Updated: 15.10.2026 18:17

Summary

PraisonAI's Async Jobs API enables its API-key middleware only when PRAISONAI_JOBS_API_KEY is set, so by default every endpoint is unauthenticated. An unauthenticated POST /api/v1/runs accepts an attacker-controlled webhook_url; on job completion the server POSTs the job payload to it via httpx. The webhook_url has an SSRF validator (gethostbyname + private-IP check), but it validates at request time while httpx re-resolves at connection time — a DNS-rebinding TOCTOU that reaches internal services. Runtime-confirmed as an unauthenticated, blind SSRF (the internal canary received the POST; the internal response is not returned to the attacker). Severity Medium.

Details

Affected component

  • Package: praisonai 4.6.63. Files: src/praisonai/praisonai/jobs/server.py, jobs/router.py, jobs/executor.py, jobs/models.py.

Vulnerable code / root cause

Path: src/praisonai/praisonai/jobs/server.py

Function: create_app

Snippet:

python
jobs_api_key = os.environ.get("PRAISONAI_JOBS_API_KEY")
# ...
if jobs_api_key:
    app.add_middleware(JobsAPIKeyMiddleware)   # auth ONLY when env var is set

Issue: with the env var unset (default), no auth middleware is added → all endpoints unauthenticated. Default bind is 127.0.0.1.

Path: src/praisonai/praisonai/jobs/router.py

Function: submit_job

Snippet:

python
@router.post("", response_model=JobSubmitResponse, status_code=202)
async def submit_job(request, response, body: JobSubmitRequest, ...):
    # no auth dependency; body.webhook_url is attacker-controlled
    job = Job(prompt=body.prompt, webhook_url=body.webhook_url, ...)
    await executor.submit(job)

Issue: attacker-controlled webhook_url flows into the job with no authentication on the endpoint.

Path: src/praisonai/praisonai/jobs/models.py (validator) and src/praisonai/praisonai/jobs/executor.py (sink)

Function: validate_webhook_url → _send_webhook

Snippet:

python
# models.py validate_webhook_url (CHECK time)
ip = socket.gethostbyname(hostname)
if ipaddress.ip_address(ip).is_private or ...:
    raise ValueError("Webhook URL resolves to a private or restricted network address")

# executor.py _send_webhook (CONNECT time, re-resolves, no pinning)
async with httpx.AsyncClient(timeout=30.0) as client:
    response = await client.post(job.webhook_url, json=payload, ...)

Issue: the validator resolves the hostname at validation time but does not pin the IP for the httpx.post connection → DNS rebinding (independent resolution at check vs connect) bypasses it and reaches internal services.

Attack flow

  1. Operator runs the Jobs API without PRAISONAI_JOBS_API_KEY (default → unauth).
  2. Attacker POST /api/v1/runs with webhook_url = a rebinding domain.
  3. The validator(s) see a public IP (pass); on completion httpx.post re-resolves to an internal IP and connects → SSRF to internal.

Why existing protection is bypassed

Auth is opt-in (only when the env var is set). The webhook_url validator resolves at check time but does not pin the IP for the connection → DNS-rebinding TOCTOU. (Correction to an earlier static note: the guard exists but is bypassable.)

Security boundary

Unauthenticated network peer → server-side request to internal services (Scope: Changed). Default bind 127.0.0.1 limits remote reach unless the operator binds non-loopback.

Proof of Concept

Environment

Real Jobs API (python -m praisonai.jobs.server, no API key) in a local runtime (127.0.0.1:18085), resolver pointed at the controlled rebinding DNS, internal canary Docker-internal only. Runnable assets: PraisonAI-Runtime-Repro\runtime-files\ (docker-compose.jobs.yml).

Steps to reproduce

  1. PRAI-04-01-Jobs-Submit-NoAuth: POST /api/v1/runs {"prompt":"hello"} → 202 (no auth).
  2. PRAI-04-02-Jobs-Webhook-SSRF-Blind: POST /api/v1/runs {"prompt":"hello","webhook_url":"http://rebind.lab:8081/secret"} → 202.

Expected result

Unauthenticated job submission should be rejected; the webhook SSRF guard should prevent reaching internal services regardless of DNS timing.

Impact

Unauthenticated job submission (LLM cost abuse); SSRF to internal services (blind, DNS-rebinding); exfiltration of the job result to an attacker-controlled webhook.

Suggested remediation

  • Authenticate the Jobs API by default (auto-generate a token / fail closed when binding non-loopback), like the gateway.
  • For webhook_url: resolve once, reject private/loopback/CGNAT/metadata, then pin and connect to the validated IP; disable redirects.

Affected software

Click a technology to see all vulnerabilities affecting it.

PlatformPackageVulnerable versionsFixed in
Python (PyPI) praisonai < 4.6.78 4.6.78

References

CVSS score 7.2/10
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Weakness (CWE)
CWE-200, CWE-306, CWE-367, CWE-918
Platform
Python (PyPI)
Package
praisonai
Disclosed
08.10.2026
Updated
15.10.2026 18:17

Sources and licenses

OSV / GitHub Advisory Database - PYSEC-2026-4249 - PyPA Advisory Database; CC BY 4.0

OSV / GitHub Advisory Database - GHSA-4w49-gwv8-fpjg - CC BY 4.0

Vulnerability history: praisonai

All published vulnerabilities of this package (Python (PyPI)), newest first. Shows whether this is a one-off slip or a package that needs watching.

All (104) in the archive
Total entries
104
First → latest
04.2026 10.2026
Without a fix
0
Exploited in attacks
0

Severity breakdown

  • Critical 27
  • High 60
  • Medium 17

Disclosures per year

  1. 2026: 104
Severity:
  1. PraisonAI: Jobs API is unauthenticated by default and allows attacker-controlled webhook SSRF this entry
    High · 7.2 CVE-2026-60091 < 4.6.78 4.6.78
  2. High · 7.5 CVE-2026-61439 < 4.6.78 4.6.78
Show more (20) Showing 20 of 87

Know which vulnerabilities affect your application

With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.

Connect your application
DockRay newsletter

Application security in your inbox

Important vulnerabilities, actionable guidance and practical advice for your applications. Choose your technologies and follow what matters to your project.

  • A daily digest of new vulnerabilities, critical ones included.
  • Notifications about important updates.
  • Practical advice on application security and monitoring.

Leave empty to receive updates for every technology.

Free to subscribe. Unsubscribe with one click in any email.