PraisonAI: AgentMail webhook lacks signature verification, allowing unauthenticated message injection and sender spoofing
🔗 CVE IDs covered (1)
📋 Description
Summary
PraisonAI's AgentMail bot, when run in webhook (or hybrid) mode, starts an aiohttp webhook server bound to 0.0.0.0 and processes inbound message.received events without verifying any signature/HMAC and without authentication. The sender address and message body are taken directly from the attacker-controlled request body, so any network peer can inject messages into the agent with a spoofed sender (bypassing sender allow/block lists) and have the agent process the content and reply to an attacker-chosen address. Sibling bots (linear.py, whatsapp.py) fail closed when no secret is configured; AgentMail omits the check entirely. Runtime-confirmed; severity Medium.
Details
Affected component
- Package:
praisonai4.6.63. File:src/praisonai/praisonai/bots/agentmail.py(AgentMailBot, webhook/hybrid mode).
Vulnerable code / root cause
Path:
src/praisonai/praisonai/bots/agentmail.py
Function:
_start_webhook_mode / _handle_email_webhook / _handle_message
Snippet:
# _start_webhook_mode: binds all interfaces
self._webhook_site = web.TCPSite(self._webhook_runner, "0.0.0.0", self._webhook_port)
# _handle_email_webhook: no signature/HMAC check, no auth
body = await request.json()
if body.get("type") != "message.received":
return web.Response(status=200, text="OK")
asyncio.create_task(self._process_webhook_payload(body)) # dispatch attacker body
return web.Response(status=200, text="OK")
# _handle_message: agent processes content, replies to attacker-controlled sender
response = await self._session.chat(self._agent, sender_id, body, ...)
await self.send_message(channel_id=sender_id, ...)
Issue: attacker-controlled input is the raw webhook JSON (from, extracted_text, subject). The guard that should exist is provider signature verification — there is none here (no svix/HMAC, no webhooks_require_verification() call). The sink is self._session.chat(self._agent, ...) (agent invocation) and send_message(channel_id=sender_id, ...) (reply to the spoofed sender). Sibling handlers src/praisonai/praisonai/bots/linear.py and bots/whatsapp.py call webhooks_require_verification() and reject when no secret is set — AgentMail does not, so it fails open.
Attack flow
- Operator runs the AgentMail bot in webhook/hybrid mode (documented; binds
0.0.0.0, default path/webhook, default port 8080). - Attacker POSTs a crafted
message.receivedevent with a spoofedfromand arbitraryextracted_text. - The agent processes the content; any reply is sent to the attacker-chosen
sender_id.
Why existing protection is bypassed
There is no protection on this handler: no signature verification, no webhooks_require_verification() gate, no auth. Sender allow/block lists are bypassed because from is attacker-controlled.
Security boundary
Unauthenticated network peer → agent message pipeline + reply destination. Crosses the bot's inbound trust boundary (provider webhooks are expected to be signed/authenticated).
Proof of Concept
Environment
Real AgentMailBot._handle_email_webhook mounted in a local runtime (127.0.0.1:18080); the agent layer is a canary recorder (/webhook-log). No real email is sent. Runnable assets: PraisonAI-Runtime-Repro\runtime-files\.
Steps to reproduce
PRAI-03-01-Webhook-Spoofed-Sender:
POST /webhook HTTP/1.1
Host: 127.0.0.1:18080
Content-Type: application/json
{"type":"message.received","data":{"from":"[email protected]","extracted_text":"PRAISONAI_WEBHOOK_INJECT_CANARY_7f3a91 ...","subject":"hello","headers":{}}}
PRAI-03-02-Agent-Reached-Response:GET /webhook-log.
Expected result
The webhook should reject unsigned/unauthenticated events; spoofed senders should not reach the agent.
Actual result
POST /webhook→200 OK(no auth/signature).GET /webhook-log→{"reached_agent":[{"sender":"[email protected]","content":"...PRAISONAI_WEBHOOK_INJECT_CANARY_7f3a91...","source":"webhook"}],"count":1}.
Impact
Unauthenticated message injection into the agent; sender spoofing (access-control bypass); agent reply/exfiltration to an attacker-chosen address; prompt-injection surface; LLM cost abuse. If the agent has dangerous tools, escalation via prompt injection is possible.
🎯 Affected products1
- pip/praisonai:<= 4.6.77