CWE-306
AllowedMissing 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.
3483 vulnerabilities reference this CWE, most recent first.
GHSA-J446-H28C-8P3V
Vulnerability from github – Published: 2026-07-01 00:34 – Updated: 2026-07-01 00:34Presenton before 0.8.8-beta bundles an MCP server that, on server/Docker deployments configured with session authentication (AUTH_USERNAME/AUTH_PASSWORD), is reachable unauthenticated at /mcp because the nginx front-end does not apply the auth_request gate to that path and the MCP server auto-mints a valid internal session token for the configured user. A remote unauthenticated attacker can invoke MCP tools such as generate_presentation, performing authenticated application actions, consuming the operators configured LLM API keys, and creating presentations in the operators instance. The Electron desktop build is not affected (MCP disabled).
{
"affected": [],
"aliases": [
"CVE-2026-58446"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-30T22:16:57Z",
"severity": "MODERATE"
},
"details": "Presenton before 0.8.8-beta bundles an MCP server that, on server/Docker deployments configured with session authentication (AUTH_USERNAME/AUTH_PASSWORD), is reachable unauthenticated at /mcp because the nginx front-end does not apply the auth_request gate to that path and the MCP server auto-mints a valid internal session token for the configured user. A remote unauthenticated attacker can invoke MCP tools such as generate_presentation, performing authenticated application actions, consuming the operators configured LLM API keys, and creating presentations in the operators instance. The Electron desktop build is not affected (MCP disabled).",
"id": "GHSA-j446-h28c-8p3v",
"modified": "2026-07-01T00:34:01Z",
"published": "2026-07-01T00:34:01Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-58446"
},
{
"type": "WEB",
"url": "https://github.com/presenton/presenton/issues/678"
},
{
"type": "WEB",
"url": "https://github.com/presenton/presenton/pull/679"
},
{
"type": "WEB",
"url": "https://github.com/presenton/presenton/commit/a1103dcef3c761cc8bab44e2862c81a49969abd7"
},
{
"type": "WEB",
"url": "https://github.com/presenton/presenton/releases/tag/electron-v0.8.8-beta"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/presenton-beta-authentication-bypass-of-session-auth-via-unprotected-mcp-endpoint"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:L/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-J4F3-55X4-R6Q2
Vulnerability from github – Published: 2026-06-18 14:26 – Updated: 2026-07-20 21:27Summary
The published npm package praisonai exports a TypeScript MCPServer that can expose tools, resources, and prompts over an HTTP JSON-RPC transport with:
await server.start({ port: 3000 });
The HTTP transport has no authentication or authorization path. MCPServerConfig does not expose an auth/security setting, startHttp() ignores the Authorization header, and every POST request is parsed and forwarded directly to handleRequest(). That request handler dispatches sensitive MCP methods such as tools/call, resources/read, and prompts/get.
The implementation also calls this.httpServer.listen(port) without a host argument. In Node.js this binds to the unspecified address; the local PoV observed { address: "::", family: "IPv6" }, making the service reachable on all interfaces on systems where the port is exposed.
This lets any network client that can reach the HTTP port list tools and invoke registered server-side tools without credentials. Supplying Authorization: Bearer invalid makes no difference.
Technical Details
MCPServerConfig exposes server metadata, tools/resources/prompts, stdio, port, and logging. It does not expose an auth token, authorization policy, MCPSecurity instance, authorization callback, or loopback-only option:
src/praisonai-ts/src/mcp/server.ts
57: export interface MCPServerConfig {
63: tools?: MCPServerTool[];
65: resources?: MCPResource[];
67: prompts?: MCPPrompt[];
69: stdio?: boolean;
73: port?: number | null;
75: logging?: boolean;
handleRequest() dispatches sensitive MCP methods directly:
src/praisonai-ts/src/mcp/server.ts
203: async handleRequest(request: MCPRequest): Promise<MCPResponse> {
219: case 'tools/call':
220: result = await this.handleToolCall(params);
225: case 'resources/read':
226: result = await this.handleResourceRead(params);
231: case 'prompts/get':
232: result = await this.handlePromptGet(params);
The tool dispatcher invokes the registered handler:
src/praisonai-ts/src/mcp/server.ts
285: private async handleToolCall(params?: any): Promise<any> {
288: const tool = this.tools.get(name);
298: const result = await tool.handler(args ?? {});
The HTTP server parses every POST body and forwards it to handleRequest() with no authentication check:
src/praisonai-ts/src/mcp/server.ts
403: async startHttp(port: number): Promise<void> {
409: this.httpServer = http.createServer(async (req, res) => {
416: const response = await this.handleRequest(request);
434: this.httpServer.listen(port, () => {
This is a guard-coverage gap because the same TypeScript package already ships a dedicated MCP security manager:
src/praisonai-ts/src/mcp/security.ts
2: * MCP Security - Authentication, authorization, and rate limiting
79: export class MCPSecurity {
132: async check(request: { path?: string; method?: string; headers?: ... })
167: const auth = headers['authorization'] ?? headers['Authorization'];
239: case 'authenticate':
303: export function createApiKeyPolicy(...)
MCPServer never references that security manager in its HTTP request path.
Why This Is Not Intended Behavior
PraisonAI's MCP documentation says MCP servers allow AI models to use tools and communicate with external systems. The same page's security considerations say to use API keys in production, implement rate limiting, validate incoming requests, use HTTPS, and limit custom tool permissions.
PraisonAI's security page also documents prior breaking hardening where API servers were changed to require authentication by default and bind to 127.0.0.1 instead of 0.0.0.0. It separately lists MCP tools/call issues as security vulnerabilities.
The npm TypeScript MCPServer does the opposite:
start({ port })binds to the unspecified address;MCPServerConfighas no auth/security field;startHttp()does not inspectAuthorization;tools/list,tools/call,resources/read, andprompts/getall dispatch without authentication; andMCPSecurityexists but is not wired into the HTTP server.
This is not merely a deployment hardening suggestion. The package exposes an HTTP MCP server API and a separate security manager, but the server's own HTTP transport provides no way to enforce the documented API-key requirement.
PoV
The PoV installs the published npm package in a temporary project, starts the exported MCPServer on a local ephemeral port, and sends loopback JSON-RPC requests. It does not call any LLM provider or external service after package installation.
Run from a local reproduction checkout:
node poc/pov_poc.js 1.7.1
Observed result:
{
"package": "praisonai",
"version": "1.7.1",
"mcpServerExported": true,
"bindAddress": {
"address": "::",
"family": "IPv6"
},
"initialize": {
"status": 200
},
"list": {
"status": 200,
"json": {
"result": {
"tools": [
{
"name": "admin_reset_marker",
"description": "privileged marker tool"
}
]
}
}
},
"callNoAuth": {
"status": 200,
"json": {
"result": {
"content": [
{
"text": "invoked:NO_AUTH_MARKER"
}
]
}
}
},
"callBadAuth": {
"status": 200,
"json": {
"result": {
"content": [
{
"text": "invoked:BAD_AUTH_MARKER"
}
]
}
}
},
"calls": [
"NO_AUTH_MARKER",
"BAD_AUTH_MARKER"
],
"patchedControl": {
"noAuthStatus": 401,
"withAuthStatus": 200,
"patchedCalls": [
"called"
]
}
}
Interpretation:
- unauthenticated
initializereturns200; - unauthenticated
tools/listreturns the registered tool; - unauthenticated
tools/callinvokes the registered tool; - invalid
Authorization: Bearer invalidis ignored and also invokes the tool; - the server binds to the unspecified IPv6 address; and
- a minimal local wrapper that enforces a bearer token blocks the same no-auth call with
401, demonstrating that the PoV is exercising the missing authentication boundary.
PoC
The PoV section above contains the local reproduction command, input, and decisive output.
Impact
Any client that can reach the npm TypeScript MCPServer HTTP port can list and invoke all registered MCP tools without credentials.
Real impact depends on which tools, resources, and prompts the application registers. MCP tools commonly wrap filesystem operations, API clients, database queries, agent actions, deployment operations, email/Slack actions, browser automation, and code execution. Because those handlers run with the server process privileges and server-side credentials, an unauthenticated caller can drive the same actions.
resources/read and prompts/get are also unauthenticated and may disclose application data or prompt material registered by the server.
Severity
Suggested severity: Critical.
Rationale:
AV: exploitation is a direct HTTP JSON-RPC request.AC: no race, user gesture, or special state is required.PR: no credentials are required; invalid credentials are ignored.UI: no user interaction is required after the server is running.S: impact is within the authority of the MCP server process and its registered tools.C: resources, prompts, and tool-returned data may expose sensitive data.I: unauthenticated callers can drive server-side tools.A: unauthenticated callers can invoke destructive or resource-consuming tools if registered.
Suggested Fix
Recommended minimum fix:
- Add
security,auth,authRequired,apiKeys, orauthorize(req)toMCPServerConfig. - Fail closed for HTTP transport when auth is not configured, unless the caller explicitly opts into unauthenticated loopback-only development mode.
- Bind HTTP transport to
127.0.0.1by default, or require an explicit host when binding to all interfaces. - Call
MCPSecurity.check(...)or equivalent middleware before every non-health POST request reacheshandleRequest(). - Return
401for missing or invalid credentials before dispatchinginitialize,tools/list,tools/call,resources/read, orprompts/get. - Add Origin/Host protections for loopback HTTP transports to reduce DNS rebinding exposure.
- Add regression tests proving:
- no-auth
tools/listreturns401; - no-auth
tools/callreturns401and does not invoke the handler; - invalid bearer token returns
401; - valid bearer token invokes the handler;
- default
start({ port })does not bind to all interfaces without an explicit opt-in.
Affected Package/Versions
- Repository:
MervinPraison/PraisonAI - Ecosystem:
npm - Package:
praisonai - Component:
src/praisonai-ts/src/mcp/server.ts - Related unused security component:
src/praisonai-ts/src/mcp/security.ts - Current npm version checked:
1.7.1 - Refreshed
origin/mainchecked:1ad58ca02975ff1398efeda694ea2ab78f20cf3e
Confirmed affected range:
>= 1.5.0, <= 1.7.1
Boundary:
1.4.0 does not export MCPServer and does not ship dist/mcp/server.js.
No fixed npm version is known at the time of this report.
Version Sweep
The included sweep installs selected npm versions and checks the HTTP MCPServer path:
node poc/version_sweep_poc.js
Observed result:
1.4.0: mcpServerExported=false, hasDistMcpServer=false
1.5.0: mcpServerExported=true, hasDistMcpServer=true, noAuthToolCallInvoked=true, bindAddress=::
1.5.4: mcpServerExported=true, hasDistMcpServer=true, noAuthToolCallInvoked=true, bindAddress=::
1.6.0: mcpServerExported=true, hasDistMcpServer=true, noAuthToolCallInvoked=true, bindAddress=::
1.7.0: mcpServerExported=true, hasDistMcpServer=true, noAuthToolCallInvoked=true, bindAddress=::
1.7.1: mcpServerExported=true, hasDistMcpServer=true, noAuthToolCallInvoked=true, bindAddress=::
Advisory History
Known related public advisories:
GHSA-9mqq-jqxf-grvw/CVE-2026-44336:pip:praisonaiMCPtools/callpath traversal to RCE in Pythonpraisonai mcp serve, affected<= 4.6.33.CVE-2026-47394:pip:praisonaiincomplete MCP path traversal fix affecting Python workflow/deploy handlers.- poc: deprecated Python MCP SSE Host/Origin/session issue.
- poc: npm TypeScript AgentOS missing authentication.
This report is distinct because it targets:
- ecosystem:
npm; - package:
praisonai; - component:
src/praisonai-ts/src/mcp/server.ts; - root cause: TypeScript
MCPServerHTTP transport missing auth and not usingMCPSecurity; - primitive: unauthenticated and invalid-auth JSON-RPC
tools/callinvokes arbitrary registered TypeScript MCP tools; and - affected range:
>= 1.5.0, <= 1.7.1.
The Python MCP advisories cover path traversal in specific Python MCP tool handlers. They do not cover the npm TypeScript MCPServer transport or its unwired security manager.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.7.1"
},
"package": {
"ecosystem": "npm",
"name": "praisonai"
},
"ranges": [
{
"events": [
{
"introduced": "1.5.0"
},
{
"fixed": "1.7.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-57139"
],
"database_specific": {
"cwe_ids": [
"CWE-1188",
"CWE-306",
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-18T14:26:48Z",
"nvd_published_at": null,
"severity": "CRITICAL"
},
"details": "## Summary\n\nThe published npm package `praisonai` exports a TypeScript `MCPServer` that can expose tools, resources, and prompts over an HTTP JSON-RPC transport with:\n\n```ts\nawait server.start({ port: 3000 });\n```\n\nThe HTTP transport has no authentication or authorization path. `MCPServerConfig` does not expose an auth/security setting, `startHttp()` ignores the `Authorization` header, and every POST request is parsed and forwarded directly to `handleRequest()`. That request handler dispatches sensitive MCP methods such as `tools/call`, `resources/read`, and `prompts/get`.\n\nThe implementation also calls `this.httpServer.listen(port)` without a host argument. In Node.js this binds to the unspecified address; the local PoV observed `{ address: \"::\", family: \"IPv6\" }`, making the service reachable on all interfaces on systems where the port is exposed.\n\nThis lets any network client that can reach the HTTP port list tools and invoke registered server-side tools without credentials. Supplying `Authorization: Bearer invalid` makes no difference.\n\n## Technical Details\n\n`MCPServerConfig` exposes server metadata, tools/resources/prompts, stdio, port, and logging. It does not expose an auth token, authorization policy, `MCPSecurity` instance, authorization callback, or loopback-only option:\n\n```text\nsrc/praisonai-ts/src/mcp/server.ts\n 57: export interface MCPServerConfig {\n 63: tools?: MCPServerTool[];\n 65: resources?: MCPResource[];\n 67: prompts?: MCPPrompt[];\n 69: stdio?: boolean;\n 73: port?: number | null;\n 75: logging?: boolean;\n```\n\n`handleRequest()` dispatches sensitive MCP methods directly:\n\n```text\nsrc/praisonai-ts/src/mcp/server.ts\n 203: async handleRequest(request: MCPRequest): Promise\u003cMCPResponse\u003e {\n 219: case \u0027tools/call\u0027:\n 220: result = await this.handleToolCall(params);\n 225: case \u0027resources/read\u0027:\n 226: result = await this.handleResourceRead(params);\n 231: case \u0027prompts/get\u0027:\n 232: result = await this.handlePromptGet(params);\n```\n\nThe tool dispatcher invokes the registered handler:\n\n```text\nsrc/praisonai-ts/src/mcp/server.ts\n 285: private async handleToolCall(params?: any): Promise\u003cany\u003e {\n 288: const tool = this.tools.get(name);\n 298: const result = await tool.handler(args ?? {});\n```\n\nThe HTTP server parses every POST body and forwards it to `handleRequest()` with no authentication check:\n\n```text\nsrc/praisonai-ts/src/mcp/server.ts\n 403: async startHttp(port: number): Promise\u003cvoid\u003e {\n 409: this.httpServer = http.createServer(async (req, res) =\u003e {\n 416: const response = await this.handleRequest(request);\n 434: this.httpServer.listen(port, () =\u003e {\n```\n\nThis is a guard-coverage gap because the same TypeScript package already ships a dedicated MCP security manager:\n\n```text\nsrc/praisonai-ts/src/mcp/security.ts\n 2: * MCP Security - Authentication, authorization, and rate limiting\n 79: export class MCPSecurity {\n 132: async check(request: { path?: string; method?: string; headers?: ... })\n 167: const auth = headers[\u0027authorization\u0027] ?? headers[\u0027Authorization\u0027];\n 239: case \u0027authenticate\u0027:\n 303: export function createApiKeyPolicy(...)\n```\n\n`MCPServer` never references that security manager in its HTTP request path.\n\n### Why This Is Not Intended Behavior\n\nPraisonAI\u0027s MCP documentation says MCP servers allow AI models to use tools and communicate with external systems. The same page\u0027s security considerations say to use API keys in production, implement rate limiting, validate incoming requests, use HTTPS, and limit custom tool permissions.\n\nPraisonAI\u0027s security page also documents prior breaking hardening where API servers were changed to require authentication by default and bind to `127.0.0.1` instead of `0.0.0.0`. It separately lists MCP `tools/call` issues as security vulnerabilities.\n\nThe npm TypeScript `MCPServer` does the opposite:\n\n- `start({ port })` binds to the unspecified address;\n- `MCPServerConfig` has no auth/security field;\n- `startHttp()` does not inspect `Authorization`;\n- `tools/list`, `tools/call`, `resources/read`, and `prompts/get` all dispatch without authentication; and\n- `MCPSecurity` exists but is not wired into the HTTP server.\n\nThis is not merely a deployment hardening suggestion. The package exposes an HTTP MCP server API and a separate security manager, but the server\u0027s own HTTP transport provides no way to enforce the documented API-key requirement.\n\n## PoV\n\nThe PoV installs the published npm package in a temporary project, starts the exported `MCPServer` on a local ephemeral port, and sends loopback JSON-RPC requests. It does not call any LLM provider or external service after package installation.\n\nRun from a local reproduction checkout:\n\n```fish\nnode poc/pov_poc.js 1.7.1\n```\n\nObserved result:\n\n```json\n{\n \"package\": \"praisonai\",\n \"version\": \"1.7.1\",\n \"mcpServerExported\": true,\n \"bindAddress\": {\n \"address\": \"::\",\n \"family\": \"IPv6\"\n },\n \"initialize\": {\n \"status\": 200\n },\n \"list\": {\n \"status\": 200,\n \"json\": {\n \"result\": {\n \"tools\": [\n {\n \"name\": \"admin_reset_marker\",\n \"description\": \"privileged marker tool\"\n }\n ]\n }\n }\n },\n \"callNoAuth\": {\n \"status\": 200,\n \"json\": {\n \"result\": {\n \"content\": [\n {\n \"text\": \"invoked:NO_AUTH_MARKER\"\n }\n ]\n }\n }\n },\n \"callBadAuth\": {\n \"status\": 200,\n \"json\": {\n \"result\": {\n \"content\": [\n {\n \"text\": \"invoked:BAD_AUTH_MARKER\"\n }\n ]\n }\n }\n },\n \"calls\": [\n \"NO_AUTH_MARKER\",\n \"BAD_AUTH_MARKER\"\n ],\n \"patchedControl\": {\n \"noAuthStatus\": 401,\n \"withAuthStatus\": 200,\n \"patchedCalls\": [\n \"called\"\n ]\n }\n}\n```\n\nInterpretation:\n\n- unauthenticated `initialize` returns `200`;\n- unauthenticated `tools/list` returns the registered tool;\n- unauthenticated `tools/call` invokes the registered tool;\n- invalid `Authorization: Bearer invalid` is ignored and also invokes the tool;\n- the server binds to the unspecified IPv6 address; and\n- a minimal local wrapper that enforces a bearer token blocks the same no-auth call with `401`, demonstrating that the PoV is exercising the missing authentication boundary.\n\n## PoC\n\nThe PoV section above contains the local reproduction command, input, and decisive output.\n\n## Impact\n\nAny client that can reach the npm TypeScript `MCPServer` HTTP port can list and invoke all registered MCP tools without credentials.\n\nReal impact depends on which tools, resources, and prompts the application registers. MCP tools commonly wrap filesystem operations, API clients, database queries, agent actions, deployment operations, email/Slack actions, browser automation, and code execution. Because those handlers run with the server process privileges and server-side credentials, an unauthenticated caller can drive the same actions.\n\n`resources/read` and `prompts/get` are also unauthenticated and may disclose application data or prompt material registered by the server.\n\n### Severity\n\nSuggested severity: Critical.\n\nRationale:\n\n- `AV`: exploitation is a direct HTTP JSON-RPC request.\n- `AC`: no race, user gesture, or special state is required.\n- `PR`: no credentials are required; invalid credentials are ignored.\n- `UI`: no user interaction is required after the server is running.\n- `S`: impact is within the authority of the MCP server process and its registered tools.\n- `C`: resources, prompts, and tool-returned data may expose sensitive data.\n- `I`: unauthenticated callers can drive server-side tools.\n- `A`: unauthenticated callers can invoke destructive or resource-consuming tools if registered.\n\n## Suggested Fix\n\nRecommended minimum fix:\n\n1. Add `security`, `auth`, `authRequired`, `apiKeys`, or `authorize(req)` to `MCPServerConfig`.\n2. Fail closed for HTTP transport when auth is not configured, unless the caller explicitly opts into unauthenticated loopback-only development mode.\n3. Bind HTTP transport to `127.0.0.1` by default, or require an explicit host when binding to all interfaces.\n4. Call `MCPSecurity.check(...)` or equivalent middleware before every non-health POST request reaches `handleRequest()`.\n5. Return `401` for missing or invalid credentials before dispatching `initialize`, `tools/list`, `tools/call`, `resources/read`, or `prompts/get`.\n6. Add Origin/Host protections for loopback HTTP transports to reduce DNS rebinding exposure.\n7. Add regression tests proving:\n - no-auth `tools/list` returns `401`;\n - no-auth `tools/call` returns `401` and does not invoke the handler;\n - invalid bearer token returns `401`;\n - valid bearer token invokes the handler;\n - default `start({ port })` does not bind to all interfaces without an explicit opt-in.\n\n## Affected Package/Versions\n\n- Repository: `MervinPraison/PraisonAI`\n- Ecosystem: `npm`\n- Package: `praisonai`\n- Component: `src/praisonai-ts/src/mcp/server.ts`\n- Related unused security component: `src/praisonai-ts/src/mcp/security.ts`\n- Current npm version checked: `1.7.1`\n- Refreshed `origin/main` checked: `1ad58ca02975ff1398efeda694ea2ab78f20cf3e`\n\nConfirmed affected range:\n\n```text\n\u003e= 1.5.0, \u003c= 1.7.1\n```\n\nBoundary:\n\n```text\n1.4.0 does not export MCPServer and does not ship dist/mcp/server.js.\n```\n\nNo fixed npm version is known at the time of this report.\n\n### Version Sweep\n\nThe included sweep installs selected npm versions and checks the HTTP `MCPServer` path:\n\n```fish\nnode poc/version_sweep_poc.js\n```\n\nObserved result:\n\n```text\n1.4.0: mcpServerExported=false, hasDistMcpServer=false\n1.5.0: mcpServerExported=true, hasDistMcpServer=true, noAuthToolCallInvoked=true, bindAddress=::\n1.5.4: mcpServerExported=true, hasDistMcpServer=true, noAuthToolCallInvoked=true, bindAddress=::\n1.6.0: mcpServerExported=true, hasDistMcpServer=true, noAuthToolCallInvoked=true, bindAddress=::\n1.7.0: mcpServerExported=true, hasDistMcpServer=true, noAuthToolCallInvoked=true, bindAddress=::\n1.7.1: mcpServerExported=true, hasDistMcpServer=true, noAuthToolCallInvoked=true, bindAddress=::\n```\n\n## Advisory History\n\nKnown related public advisories:\n\n- `GHSA-9mqq-jqxf-grvw` / `CVE-2026-44336`: `pip:praisonai` MCP `tools/call` path traversal to RCE in Python `praisonai mcp serve`, affected `\u003c= 4.6.33`.\n- `CVE-2026-47394`: `pip:praisonai` incomplete MCP path traversal fix affecting Python workflow/deploy handlers.\n- poc: deprecated Python MCP SSE Host/Origin/session issue.\n- poc: npm TypeScript AgentOS missing authentication.\n\nThis report is distinct because it targets:\n\n- ecosystem: `npm`;\n- package: `praisonai`;\n- component: `src/praisonai-ts/src/mcp/server.ts`;\n- root cause: TypeScript `MCPServer` HTTP transport missing auth and not using `MCPSecurity`;\n- primitive: unauthenticated and invalid-auth JSON-RPC `tools/call` invokes arbitrary registered TypeScript MCP tools; and\n- affected range: `\u003e= 1.5.0, \u003c= 1.7.1`.\n\nThe Python MCP advisories cover path traversal in specific Python MCP tool handlers. They do not cover the npm TypeScript `MCPServer` transport or its unwired security manager.",
"id": "GHSA-j4f3-55x4-r6q2",
"modified": "2026-07-20T21:27:31Z",
"published": "2026-06-18T14:26:48Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-j4f3-55x4-r6q2"
},
{
"type": "PACKAGE",
"url": "https://github.com/MervinPraison/PraisonAI"
}
],
"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"
}
],
"summary": "npm PraisonAI MCPServer exposes unauthenticated HTTP tools/call"
}
GHSA-J4G8-8JW2-7WW9
Vulnerability from github – Published: 2024-09-11 09:31 – Updated: 2024-09-11 09:31The WooCommerce Photo Reviews Premium plugin for WordPress is vulnerable to authentication bypass in all versions up to, and including, 1.3.13.2. This is due to the plugin not properly validating what user transient is being used in the login() function and not properly verifying the user's identity. This makes it possible for unauthenticated attackers to log in as user that has dismissed an admin notice in the past 30 days, which is often an administrator. Alternatively, a user can log in as any user with any transient that has a valid user_id as the value, though it would be more difficult to exploit this successfully.
{
"affected": [],
"aliases": [
"CVE-2024-8277"
],
"database_specific": {
"cwe_ids": [
"CWE-288",
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-09-11T09:15:02Z",
"severity": "CRITICAL"
},
"details": "The WooCommerce Photo Reviews Premium plugin for WordPress is vulnerable to authentication bypass in all versions up to, and including, 1.3.13.2. This is due to the plugin not properly validating what user transient is being used in the login() function and not properly verifying the user\u0027s identity. This makes it possible for unauthenticated attackers to log in as user that has dismissed an admin notice in the past 30 days, which is often an administrator. Alternatively, a user can log in as any user with any transient that has a valid user_id as the value, though it would be more difficult to exploit this successfully.",
"id": "GHSA-j4g8-8jw2-7ww9",
"modified": "2024-09-11T09:31:12Z",
"published": "2024-09-11T09:31:12Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-8277"
},
{
"type": "WEB",
"url": "https://codecanyon.net/item/woocommerce-photo-reviews/21245349"
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/a1e2d370-a716-4d6b-8e23-74db2fbd0760?source=cve"
}
],
"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-J4HJ-7HFH-G2F4
Vulnerability from github – Published: 2026-06-18 13:56 – Updated: 2026-07-20 21:25praisonai: recipe serve authentication middleware silently disables itself when no secret is set
Researcher: Kai Aizen — SnailSploit (@SnailSploit), Adversarial & Offensive Security Research Target: https://github.com/MervinPraison/PraisonAI
Package: praisonai on PyPI
Version tested: 4.6.48.
File: praisonai/recipe/serve.py (sha256 491bf8f29e399418260810ba4bf0f6802c6e4aa675628e2be68a9726c15d9b23).
TL;DR
praisonai/recipe/serve.py:312-410 defines two auth middlewares (APIKeyAuthMiddleware, JWTAuthMiddleware). Both contain the same "fail open when the secret is unset" branch at the top of their dispatch:
async def dispatch(self, request, call_next):
if request.url.path == "/health":
return await call_next(request)
expected_key = api_key or os.environ.get("PRAISONAI_API_KEY")
if not expected_key:
# No key configured, allow request
return await call_next(request)
...
async def dispatch(self, request, call_next):
if request.url.path == "/health":
return await call_next(request)
secret = jwt_secret or os.environ.get("PRAISONAI_JWT_SECRET")
if not secret:
return await call_next(request)
...
The realistic mis-deploy:
- operator sets
auth: api-key(orauth: jwt) in their recipe YAML, expecting that line alone to enable auth, - operator does not set the corresponding
api_key:/jwt_secret:value in the same YAML, AND - operator does not export
PRAISONAI_API_KEY/PRAISONAI_JWT_SECRETin the environment.
The middleware silently treats every request as authenticated and forwards it to the recipe-execution route.
Combined with the praisonai jobs API having zero auth (a separate finding), operators who paid attention to "I have to set auth: api-key to lock this down" still don't get auth on the recipe-serve surface unless they also remember the secret.
Root cause
Expected behavior, after setting `auth: api-key` in the recipe YAML:
"Now my recipe endpoints require an X-API-Key header."
Actual behavior (serve.py:325-333):
- middleware reads `expected_key = api_key or
os.environ.get("PRAISONAI_API_KEY")`
- if `expected_key` is None (neither YAML nor env supplied
one), middleware logs nothing and forwards the request.
- operator's recipe routes accept the request as if it were
authenticated. request.state.user is unset.
Impact:
The middleware's documented job is "validate the API key
against the configured value". The configured-value-is-None
case is exactly the case the middleware should fail closed
on — operator has signalled they want auth. Failing open
silently turns a documented authentication into a runtime
no-op.
Empirical verification
poc/poc.py:
- Imports the installed praisonai 4.6.48
praisonai.recipe.servemodule (sha256491bf8f29e399418260810ba4bf0f6802c6e4aa675628e2be68a9726c15d9b23). - Clears
PRAISONAI_API_KEY/PRAISONAI_JWT_SECRETenv vars to simulate the mis-deploy. - Calls
serve.create_auth_middleware('api-key', api_key=None, jwt_secret=None)and instantiates the returned middleware. - Builds a Starlette
Requestfor/runs(the recipe-execution path) with empty headers — noX-API-Key, noAuthorization. await middleware.dispatch(request, fake_call_next)returns the sentinel'REACHED-DOWNSTREAM (path=/runs)'from the fakecall_next— proving the middleware passed the request through without authenticating.- Repeats the test for
auth_type='jwt'— same bypass on the JWT path.
Run log (poc/run-log.txt) summary:
[2] auth_type='api-key', no api_key / no PRAISONAI_API_KEY env
middleware.dispatch -> 'REACHED-DOWNSTREAM (path=/runs)'
[3] auth_type='jwt', no jwt_secret / no PRAISONAI_JWT_SECRET env
middleware.dispatch -> 'REACHED-DOWNSTREAM (path=/runs)'
APIKeyAuthMiddleware allowed the request through without an API key.
JWTAuthMiddleware allowed the request through without a Bearer token.
[4] grep '# No key configured, allow request' -> line 333
VERDICT: VULNERABLE
EXIT 0
Impact
The recipe-serve surface runs agentic workflows — same execution posture as praisonai/jobs/server.py but separately configured / separately reached. Unauth access on this surface yields:
- Trigger arbitrary recipe executions, passing attacker-controlled inputs and configurations.
- Read the inputs / outputs of in-flight recipes — the operator's prompts and the LLM responses.
- In some deployments, the recipe execution surface is wired to tools (browser automation, file-system writes, code execution). Reaching those tools without auth is a direct RCE path.
Anchors
praisonai/recipe/serve.py:325-333—APIKeyAuthMiddleware.dispatchsilent-bypass branch.praisonai/recipe/serve.py:352-355—JWTAuthMiddleware.dispatchsilent-bypass branch.praisonai/recipe/serve.py:688-694— call site:python auth_type = config.get("auth") if auth_type and auth_type != "none": auth_middleware = create_auth_middleware( auth_type, api_key=config.get("api_key"), jwt_secret=config.get("jwt_secret"), )
Suggested fix
When the operator has signalled "I want auth", refuse to start without the corresponding secret rather than silently degrading:
def create_auth_middleware(auth_type, api_key=None, jwt_secret=None):
if auth_type == 'api-key':
expected_key = api_key or os.environ.get("PRAISONAI_API_KEY")
if not expected_key:
raise SystemExit(
"auth_type='api-key' requested but no API key is "
"configured. Either set `api_key:` in your recipe "
"YAML or export PRAISONAI_API_KEY. Refusing to "
"start with a silently disabled auth middleware."
)
...
elif auth_type == 'jwt':
secret = jwt_secret or os.environ.get("PRAISONAI_JWT_SECRET")
if not secret:
raise SystemExit(
"auth_type='jwt' requested but no JWT secret is "
"configured. Either set `jwt_secret:` in your recipe "
"YAML or export PRAISONAI_JWT_SECRET. Refusing to "
"start with a silently disabled auth middleware."
)
...
This is the same pattern the sibling praisonai.gateway server applies in assert_external_bind_safe at praisonai/gateway/auth.py:48-54 — refuse-to-start on external bind without an auth token. The recipe-serve surface should do the same.
Steps to reproduce
- Clone the target:
git clone --depth 1 https://github.com/MervinPraison/PraisonAI - Run the proof of concept (
poc.py) against the cloned source. - Observe the result shown under Verified result below.
Proof of concept
poc.py
"""
PoC: praisonai 4.6.48 `praisonai recipe serve` configures
authentication via a `auth:` field in the recipe YAML. Setting
`auth: api-key` or `auth: jwt` installs APIKeyAuthMiddleware or
JWTAuthMiddleware on the FastAPI app — and the operator's expectation
is that those endpoints now require a valid API key / Bearer JWT.
In reality, both middlewares contain an early-return that silently
bypasses authentication when the corresponding secret has not been
configured (neither via the recipe YAML nor via the
PRAISONAI_API_KEY / PRAISONAI_JWT_SECRET env var).
"""
import hashlib
import inspect
import os
import sys
def main() -> int:
print('=' * 72)
print('praisonai 4.6.48 — recipe serve auth middleware silent bypass')
print('=' * 72)
# Realistic deploy: operator sets `auth: api-key` in YAML but
# forgets to set api_key / env var.
for env_var in ('PRAISONAI_API_KEY', 'PRAISONAI_JWT_SECRET'):
if env_var in os.environ:
del os.environ[env_var]
from praisonai.recipe import serve as serve_mod
src = inspect.getsourcefile(serve_mod)
with open(src, 'rb') as f:
raw = f.read()
sha = hashlib.sha256(raw).hexdigest()
print()
print(f'[1] serve.py path : {src}')
print(f' sha256 : {sha}')
from starlette.requests import Request
create_auth_middleware = serve_mod.create_auth_middleware
async def fake_call_next(request):
return f"REACHED-DOWNSTREAM (path={request.url.path})"
async def driver(auth_type: str, headers=None):
scope = {
'type': 'http', 'method': 'GET', 'path': '/runs',
'headers': headers or [], 'query_string': b'', 'scheme': 'http',
'server': ('127.0.0.1', 8000), 'app': None, 'root_path': '',
}
request = Request(scope, receive=lambda: None)
mw_cls = create_auth_middleware(auth_type, api_key=None, jwt_secret=None)
if mw_cls is None:
return 'middleware-import-failed'
instance = mw_cls(app=None)
return await instance.dispatch(request, fake_call_next)
import asyncio
print()
print("[2] auth_type='api-key', no api_key / no PRAISONAI_API_KEY env")
result_apikey = asyncio.run(driver('api-key'))
print(f" middleware.dispatch -> {result_apikey!r}")
print()
print("[3] auth_type='jwt', no jwt_secret / no PRAISONAI_JWT_SECRET env")
result_jwt = asyncio.run(driver('jwt'))
print(f" middleware.dispatch -> {result_jwt!r}")
vulnerable = False
if isinstance(result_apikey, str) and 'REACHED-DOWNSTREAM' in result_apikey:
vulnerable = True
print(' APIKeyAuthMiddleware allowed the request through without an API key.')
if isinstance(result_jwt, str) and 'REACHED-DOWNSTREAM' in result_jwt:
vulnerable = True
print(' JWTAuthMiddleware allowed the request through without a Bearer token.')
# Static check that the bypass is on the code path.
text = raw.decode('utf-8', errors='replace')
needle_api = '# No key configured, allow request'
apikey_line = next(
(i for i, l in enumerate(text.splitlines(), 1) if needle_api in l),
None,
)
print()
print('[4] static cross-check — bypass branch on the code path')
print(f" grep '{needle_api}' -> line {apikey_line}")
if not vulnerable:
print('UNEXPECTED — the dispatch did not return the bypass result.')
return 1
print()
print('VULNERABLE: praisonai 4.6.48 `recipe serve` AuthMiddleware classes')
print(' both silently bypass auth when the operator sets auth_type')
print(' but forgets the corresponding secret — unauthenticated access')
print(' to recipe execution endpoints.')
print('VERDICT: VULNERABLE')
return 0
if __name__ == '__main__':
sys.exit(main())
Verification harness (executed against the cloned repo)
This drives the unmodified upstream code rather than a reproduction.
import sys, types, os, importlib.util
BK=os.path.abspath("repos/PraisonAI/src/praisonai"); sys.path.insert(0,BK)
for p in ["praisonai","praisonai.recipe"]:
m=types.ModuleType(p); m.__path__=[BK+"/"+p.replace(".","/")]; sys.modules[p]=m
spec=importlib.util.spec_from_file_location("praisonai.recipe.serve", BK+"/praisonai/recipe/serve.py")
serve=importlib.util.module_from_spec(spec); serve.__package__="praisonai.recipe"; sys.modules[spec.name]=serve; spec.loader.exec_module(serve)
print("[*] Loaded REAL praisonai recipe/serve.py")
os.environ.pop("PRAISONAI_API_KEY", None) # operator forgot to export it too
from starlette.applications import Starlette
from starlette.routing import Route
from starlette.responses import PlainTextResponse
from starlette.testclient import TestClient
def make_app(mw):
app=Starlette(routes=[Route("/run", lambda r: PlainTextResponse("AGENT EXECUTED"), methods=["POST"])])
app.add_middleware(mw); return TestClient(app)
# (A) operator set `auth: api-key` but forgot api_key + env -> REAL factory returns middleware that SILENTLY bypasses
MW_bypass = serve.create_auth_middleware("api-key", api_key=None) # REAL factory
r = make_app(MW_bypass).post("/run")
print(f"[+] auth='api-key', NO key configured, NO header -> HTTP {r.status_code} body={r.text!r}")
# (B) control: same middleware WITH a key configured -> unauthenticated request is correctly 401
MW_enforced = serve.create_auth_middleware("api-key", api_key="real-secret")
r2 = make_app(MW_enforced).post("/run")
print(f"[*] auth='api-key', key CONFIGURED, NO header -> HTTP {r2.status_code} (correctly rejected)")
assert r.status_code==200 and "AGENT EXECUTED" in r.text and r2.status_code==401
print("[+] CONFIRMED against real praisonai repo: APIKeyAuthMiddleware silently bypasses auth when no key configured -> agent route reachable unauthenticated")
Verified result
This PoC was executed against the live upstream code; captured output:
[*] Loaded REAL praisonai recipe/serve.py
[+] auth='api-key', NO key configured, NO header -> HTTP 200 body='AGENT EXECUTED'
[*] auth='api-key', key CONFIGURED, NO header -> HTTP 401 (correctly rejected)
[+] CONFIRMED against real praisonai repo: APIKeyAuthMiddleware silently bypasses auth when no key configured -> agent route reachable unauthenticated
Credit
Kai Aizen — SnailSploit (@SnailSploit). Adversarial & Offensive Security Research.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.6.48"
},
"package": {
"ecosystem": "PyPI",
"name": "praisonai"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.6.59"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-57127"
],
"database_specific": {
"cwe_ids": [
"CWE-1188",
"CWE-306"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-18T13:56:55Z",
"nvd_published_at": null,
"severity": "CRITICAL"
},
"details": "# praisonai: `recipe serve` authentication middleware silently disables itself when no secret is set\n\n**Researcher:** Kai Aizen \u2014 SnailSploit (@SnailSploit), Adversarial \u0026 Offensive Security Research\n**Target:** https://github.com/MervinPraison/PraisonAI\n\n---\n\n**Package:** `praisonai` on PyPI\n**Version tested:** 4.6.48.\n**File:** `praisonai/recipe/serve.py` (sha256 `491bf8f29e399418260810ba4bf0f6802c6e4aa675628e2be68a9726c15d9b23`).\n\n---\n\n## TL;DR\n\n`praisonai/recipe/serve.py:312-410` defines two auth middlewares (`APIKeyAuthMiddleware`, `JWTAuthMiddleware`). Both contain the same \"fail open when the secret is unset\" branch at the top of their `dispatch`:\n\n```python\nasync def dispatch(self, request, call_next):\n if request.url.path == \"/health\":\n return await call_next(request)\n expected_key = api_key or os.environ.get(\"PRAISONAI_API_KEY\")\n if not expected_key:\n # No key configured, allow request\n return await call_next(request)\n ...\n```\n\n```python\nasync def dispatch(self, request, call_next):\n if request.url.path == \"/health\":\n return await call_next(request)\n secret = jwt_secret or os.environ.get(\"PRAISONAI_JWT_SECRET\")\n if not secret:\n return await call_next(request)\n ...\n```\n\nThe realistic mis-deploy:\n\n1. operator sets `auth: api-key` (or `auth: jwt`) in their recipe YAML, expecting that line alone to enable auth,\n2. operator does not set the corresponding `api_key:` / `jwt_secret:` value in the same YAML, AND\n3. operator does not export `PRAISONAI_API_KEY` / `PRAISONAI_JWT_SECRET` in the environment.\n\nThe middleware silently treats every request as authenticated and forwards it to the recipe-execution route.\n\nCombined with the praisonai jobs API having zero auth (a separate finding), operators who paid attention to \"I have to set `auth: api-key` to lock this down\" still don\u0027t get auth on the recipe-serve surface unless they also remember the secret.\n\n## Root cause\n\n```\n Expected behavior, after setting `auth: api-key` in the recipe YAML:\n \"Now my recipe endpoints require an X-API-Key header.\"\n\n Actual behavior (serve.py:325-333):\n - middleware reads `expected_key = api_key or\n os.environ.get(\"PRAISONAI_API_KEY\")`\n - if `expected_key` is None (neither YAML nor env supplied\n one), middleware logs nothing and forwards the request.\n - operator\u0027s recipe routes accept the request as if it were\n authenticated. request.state.user is unset.\n\n Impact:\n The middleware\u0027s documented job is \"validate the API key\n against the configured value\". The configured-value-is-None\n case is exactly the case the middleware should fail closed\n on \u2014 operator has signalled they want auth. Failing open\n silently turns a documented authentication into a runtime\n no-op.\n```\n\n## Empirical verification\n\n`poc/poc.py`:\n\n1. Imports the installed praisonai 4.6.48 `praisonai.recipe.serve` module (sha256 `491bf8f29e399418260810ba4bf0f6802c6e4aa675628e2be68a9726c15d9b23`).\n2. Clears `PRAISONAI_API_KEY` / `PRAISONAI_JWT_SECRET` env vars to simulate the mis-deploy.\n3. Calls `serve.create_auth_middleware(\u0027api-key\u0027, api_key=None, jwt_secret=None)` and instantiates the returned middleware.\n4. Builds a Starlette `Request` for `/runs` (the recipe-execution path) with empty headers \u2014 no `X-API-Key`, no `Authorization`.\n5. `await middleware.dispatch(request, fake_call_next)` returns the sentinel `\u0027REACHED-DOWNSTREAM (path=/runs)\u0027` from the fake `call_next` \u2014 proving the middleware passed the request through without authenticating.\n6. Repeats the test for `auth_type=\u0027jwt\u0027` \u2014 same bypass on the JWT path.\n\nRun log (`poc/run-log.txt`) summary:\n\n```\n[2] auth_type=\u0027api-key\u0027, no api_key / no PRAISONAI_API_KEY env\n middleware.dispatch -\u003e \u0027REACHED-DOWNSTREAM (path=/runs)\u0027\n[3] auth_type=\u0027jwt\u0027, no jwt_secret / no PRAISONAI_JWT_SECRET env\n middleware.dispatch -\u003e \u0027REACHED-DOWNSTREAM (path=/runs)\u0027\n APIKeyAuthMiddleware allowed the request through without an API key.\n JWTAuthMiddleware allowed the request through without a Bearer token.\n[4] grep \u0027# No key configured, allow request\u0027 -\u003e line 333\n\nVERDICT: VULNERABLE\nEXIT 0\n```\n\n## Impact\n\nThe recipe-serve surface runs agentic workflows \u2014 same execution posture as `praisonai/jobs/server.py` but separately configured / separately reached. Unauth access on this surface yields:\n\n- Trigger arbitrary recipe executions, passing attacker-controlled inputs and configurations.\n- Read the inputs / outputs of in-flight recipes \u2014 the operator\u0027s prompts and the LLM responses.\n- In some deployments, the recipe execution surface is wired to tools (browser automation, file-system writes, code execution). Reaching those tools without auth is a direct RCE path.\n\n\n## Anchors\n\n- `praisonai/recipe/serve.py:325-333` \u2014 `APIKeyAuthMiddleware.dispatch` silent-bypass branch.\n- `praisonai/recipe/serve.py:352-355` \u2014 `JWTAuthMiddleware.dispatch` silent-bypass branch.\n- `praisonai/recipe/serve.py:688-694` \u2014 call site:\n ```python\n auth_type = config.get(\"auth\")\n if auth_type and auth_type != \"none\":\n auth_middleware = create_auth_middleware(\n auth_type,\n api_key=config.get(\"api_key\"),\n jwt_secret=config.get(\"jwt_secret\"),\n )\n ```\n\n## Suggested fix\n\nWhen the operator has signalled \"I want auth\", refuse to start without the corresponding secret rather than silently degrading:\n\n```python\ndef create_auth_middleware(auth_type, api_key=None, jwt_secret=None):\n if auth_type == \u0027api-key\u0027:\n expected_key = api_key or os.environ.get(\"PRAISONAI_API_KEY\")\n if not expected_key:\n raise SystemExit(\n \"auth_type=\u0027api-key\u0027 requested but no API key is \"\n \"configured. Either set `api_key:` in your recipe \"\n \"YAML or export PRAISONAI_API_KEY. Refusing to \"\n \"start with a silently disabled auth middleware.\"\n )\n ...\n elif auth_type == \u0027jwt\u0027:\n secret = jwt_secret or os.environ.get(\"PRAISONAI_JWT_SECRET\")\n if not secret:\n raise SystemExit(\n \"auth_type=\u0027jwt\u0027 requested but no JWT secret is \"\n \"configured. Either set `jwt_secret:` in your recipe \"\n \"YAML or export PRAISONAI_JWT_SECRET. Refusing to \"\n \"start with a silently disabled auth middleware.\"\n )\n ...\n```\n\nThis is the same pattern the sibling `praisonai.gateway` server applies in `assert_external_bind_safe` at `praisonai/gateway/auth.py:48-54` \u2014 refuse-to-start on external bind without an auth token. The recipe-serve surface should do the same.\n\n## Steps to reproduce\n\n1. Clone the target: `git clone --depth 1 https://github.com/MervinPraison/PraisonAI`\n2. Run the proof of concept (`poc.py`) against the cloned source.\n3. Observe the result shown under *Verified result* below.\n\n## Proof of concept\n\n`poc.py`\n\n```python\n\"\"\"\nPoC: praisonai 4.6.48 `praisonai recipe serve` configures\nauthentication via a `auth:` field in the recipe YAML. Setting\n`auth: api-key` or `auth: jwt` installs APIKeyAuthMiddleware or\nJWTAuthMiddleware on the FastAPI app \u2014 and the operator\u0027s expectation\nis that those endpoints now require a valid API key / Bearer JWT.\n\nIn reality, both middlewares contain an early-return that silently\nbypasses authentication when the corresponding secret has not been\nconfigured (neither via the recipe YAML nor via the\nPRAISONAI_API_KEY / PRAISONAI_JWT_SECRET env var).\n\"\"\"\n\nimport hashlib\nimport inspect\nimport os\nimport sys\n\ndef main() -\u003e int:\n print(\u0027=\u0027 * 72)\n print(\u0027praisonai 4.6.48 \u2014 recipe serve auth middleware silent bypass\u0027)\n print(\u0027=\u0027 * 72)\n\n # Realistic deploy: operator sets `auth: api-key` in YAML but\n # forgets to set api_key / env var.\n for env_var in (\u0027PRAISONAI_API_KEY\u0027, \u0027PRAISONAI_JWT_SECRET\u0027):\n if env_var in os.environ:\n del os.environ[env_var]\n\n from praisonai.recipe import serve as serve_mod\n\n src = inspect.getsourcefile(serve_mod)\n with open(src, \u0027rb\u0027) as f:\n raw = f.read()\n sha = hashlib.sha256(raw).hexdigest()\n\n print()\n print(f\u0027[1] serve.py path : {src}\u0027)\n print(f\u0027 sha256 : {sha}\u0027)\n\n from starlette.requests import Request\n create_auth_middleware = serve_mod.create_auth_middleware\n\n async def fake_call_next(request):\n return f\"REACHED-DOWNSTREAM (path={request.url.path})\"\n\n async def driver(auth_type: str, headers=None):\n scope = {\n \u0027type\u0027: \u0027http\u0027, \u0027method\u0027: \u0027GET\u0027, \u0027path\u0027: \u0027/runs\u0027,\n \u0027headers\u0027: headers or [], \u0027query_string\u0027: b\u0027\u0027, \u0027scheme\u0027: \u0027http\u0027,\n \u0027server\u0027: (\u0027127.0.0.1\u0027, 8000), \u0027app\u0027: None, \u0027root_path\u0027: \u0027\u0027,\n }\n request = Request(scope, receive=lambda: None)\n mw_cls = create_auth_middleware(auth_type, api_key=None, jwt_secret=None)\n if mw_cls is None:\n return \u0027middleware-import-failed\u0027\n instance = mw_cls(app=None)\n return await instance.dispatch(request, fake_call_next)\n\n import asyncio\n\n print()\n print(\"[2] auth_type=\u0027api-key\u0027, no api_key / no PRAISONAI_API_KEY env\")\n result_apikey = asyncio.run(driver(\u0027api-key\u0027))\n print(f\" middleware.dispatch -\u003e {result_apikey!r}\")\n\n print()\n print(\"[3] auth_type=\u0027jwt\u0027, no jwt_secret / no PRAISONAI_JWT_SECRET env\")\n result_jwt = asyncio.run(driver(\u0027jwt\u0027))\n print(f\" middleware.dispatch -\u003e {result_jwt!r}\")\n\n vulnerable = False\n if isinstance(result_apikey, str) and \u0027REACHED-DOWNSTREAM\u0027 in result_apikey:\n vulnerable = True\n print(\u0027 APIKeyAuthMiddleware allowed the request through without an API key.\u0027)\n if isinstance(result_jwt, str) and \u0027REACHED-DOWNSTREAM\u0027 in result_jwt:\n vulnerable = True\n print(\u0027 JWTAuthMiddleware allowed the request through without a Bearer token.\u0027)\n\n # Static check that the bypass is on the code path.\n text = raw.decode(\u0027utf-8\u0027, errors=\u0027replace\u0027)\n needle_api = \u0027# No key configured, allow request\u0027\n apikey_line = next(\n (i for i, l in enumerate(text.splitlines(), 1) if needle_api in l),\n None,\n )\n print()\n print(\u0027[4] static cross-check \u2014 bypass branch on the code path\u0027)\n print(f\" grep \u0027{needle_api}\u0027 -\u003e line {apikey_line}\")\n\n if not vulnerable:\n print(\u0027UNEXPECTED \u2014 the dispatch did not return the bypass result.\u0027)\n return 1\n\n print()\n print(\u0027VULNERABLE: praisonai 4.6.48 `recipe serve` AuthMiddleware classes\u0027)\n print(\u0027 both silently bypass auth when the operator sets auth_type\u0027)\n print(\u0027 but forgets the corresponding secret \u2014 unauthenticated access\u0027)\n print(\u0027 to recipe execution endpoints.\u0027)\n print(\u0027VERDICT: VULNERABLE\u0027)\n return 0\n\nif __name__ == \u0027__main__\u0027:\n sys.exit(main())\n```\n\n## Verification harness (executed against the cloned repo)\n\nThis drives the unmodified upstream code rather than a reproduction.\n\n```python\nimport sys, types, os, importlib.util\nBK=os.path.abspath(\"repos/PraisonAI/src/praisonai\"); sys.path.insert(0,BK)\nfor p in [\"praisonai\",\"praisonai.recipe\"]:\n m=types.ModuleType(p); m.__path__=[BK+\"/\"+p.replace(\".\",\"/\")]; sys.modules[p]=m\nspec=importlib.util.spec_from_file_location(\"praisonai.recipe.serve\", BK+\"/praisonai/recipe/serve.py\")\nserve=importlib.util.module_from_spec(spec); serve.__package__=\"praisonai.recipe\"; sys.modules[spec.name]=serve; spec.loader.exec_module(serve)\nprint(\"[*] Loaded REAL praisonai recipe/serve.py\")\nos.environ.pop(\"PRAISONAI_API_KEY\", None) # operator forgot to export it too\n\nfrom starlette.applications import Starlette\nfrom starlette.routing import Route\nfrom starlette.responses import PlainTextResponse\nfrom starlette.testclient import TestClient\ndef make_app(mw):\n app=Starlette(routes=[Route(\"/run\", lambda r: PlainTextResponse(\"AGENT EXECUTED\"), methods=[\"POST\"])])\n app.add_middleware(mw); return TestClient(app)\n\n# (A) operator set `auth: api-key` but forgot api_key + env -\u003e REAL factory returns middleware that SILENTLY bypasses\nMW_bypass = serve.create_auth_middleware(\"api-key\", api_key=None) # REAL factory\nr = make_app(MW_bypass).post(\"/run\")\nprint(f\"[+] auth=\u0027api-key\u0027, NO key configured, NO header -\u003e HTTP {r.status_code} body={r.text!r}\")\n\n# (B) control: same middleware WITH a key configured -\u003e unauthenticated request is correctly 401\nMW_enforced = serve.create_auth_middleware(\"api-key\", api_key=\"real-secret\")\nr2 = make_app(MW_enforced).post(\"/run\")\nprint(f\"[*] auth=\u0027api-key\u0027, key CONFIGURED, NO header -\u003e HTTP {r2.status_code} (correctly rejected)\")\n\nassert r.status_code==200 and \"AGENT EXECUTED\" in r.text and r2.status_code==401\nprint(\"[+] CONFIRMED against real praisonai repo: APIKeyAuthMiddleware silently bypasses auth when no key configured -\u003e agent route reachable unauthenticated\")\n```\n\n## Verified result\n\nThis PoC was executed against the live upstream code; captured output:\n\n```\n[*] Loaded REAL praisonai recipe/serve.py\n[+] auth=\u0027api-key\u0027, NO key configured, NO header -\u003e HTTP 200 body=\u0027AGENT EXECUTED\u0027\n[*] auth=\u0027api-key\u0027, key CONFIGURED, NO header -\u003e HTTP 401 (correctly rejected)\n[+] CONFIRMED against real praisonai repo: APIKeyAuthMiddleware silently bypasses auth when no key configured -\u003e agent route reachable unauthenticated\n```\n\n## Credit\n\nKai Aizen \u2014 SnailSploit (@SnailSploit). Adversarial \u0026 Offensive Security Research.",
"id": "GHSA-j4hj-7hfh-g2f4",
"modified": "2026-07-20T21:25:31Z",
"published": "2026-06-18T13:56:55Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-j4hj-7hfh-g2f4"
},
{
"type": "PACKAGE",
"url": "https://github.com/MervinPraison/PraisonAI"
}
],
"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"
}
],
"summary": "praisonai: recipe serve auth middleware silently disables itself when no secret is set"
}
GHSA-J4J8-2VCC-42HJ
Vulnerability from github – Published: 2025-11-10 21:30 – Updated: 2025-11-10 21:30Policy bypass in Extensions in Google Chrome prior to 142.0.7444.59 allowed an attacker who convinced a user to install a malicious extension to obtain potentially sensitive information from process memory via a crafted Chrome Extension. (Chromium security severity: Medium)
{
"affected": [],
"aliases": [
"CVE-2025-12436"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-11-10T20:15:38Z",
"severity": "MODERATE"
},
"details": "Policy bypass in Extensions in Google Chrome prior to 142.0.7444.59 allowed an attacker who convinced a user to install a malicious extension to obtain potentially sensitive information from process memory via a crafted Chrome Extension. (Chromium security severity: Medium)",
"id": "GHSA-j4j8-2vcc-42hj",
"modified": "2025-11-10T21:30:35Z",
"published": "2025-11-10T21:30:35Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-12436"
},
{
"type": "WEB",
"url": "https://chromereleases.googleblog.com/2025/10/stable-channel-update-for-desktop_28.html"
},
{
"type": "WEB",
"url": "https://issues.chromium.org/issues/40054742"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-J4P8-5VJ7-45MF
Vulnerability from github – Published: 2025-12-24 06:30 – Updated: 2025-12-24 06:30Authorization bypass vulnerability in Hitachi Infrastructure Analytics Advisor (Data Center Analytics component) and Hitachi Ops Center Analyzer (Hitachi Ops Center Analyzer detail view component).This issue affects Hitachi Infrastructure Analytics Advisor:; Hitachi Ops Center Analyzer: from 10.0.0-00 before 11.0.5-00.
{
"affected": [],
"aliases": [
"CVE-2025-66445"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-12-24T05:16:08Z",
"severity": "HIGH"
},
"details": "Authorization bypass vulnerability in Hitachi Infrastructure Analytics Advisor (Data Center Analytics component) and Hitachi Ops Center Analyzer (Hitachi Ops Center Analyzer detail view component).This issue affects Hitachi Infrastructure Analytics Advisor:; Hitachi Ops Center Analyzer: from 10.0.0-00 before 11.0.5-00.",
"id": "GHSA-j4p8-5vj7-45mf",
"modified": "2025-12-24T06:30:26Z",
"published": "2025-12-24T06:30:26Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-66445"
},
{
"type": "WEB",
"url": "https://www.hitachi.com/products/it/software/security/info/vuls/hitachi-sec-2025-133/index.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-J4PP-RP58-2QHJ
Vulnerability from github – Published: 2023-04-20 00:30 – Updated: 2024-04-04 03:36The Flexi Classic and Flexi Soft Gateways SICK UE410-EN3 FLEXI ETHERNET GATEW., SICK UE410-EN1 FLEXI ETHERNET GATEW., SICK UE410-EN3S04 FLEXI ETHERNET GATEW., SICK UE410-EN4 FLEXI ETHERNET GATEW., SICK FX0-GENT00000 FLEXISOFT EIP GATEW., SICK FX0-GMOD00000 FLEXISOFT MOD GATEW., SICK FX0-GPNT00000 FLEXISOFT PNET GATEW., SICK FX0-GENT00030 FLEXISOFT EIP GATEW.V2, SICK FX0-GPNT00030 FLEXISOFT PNET GATEW.V2 and SICK FX0-GMOD00010 FLEXISOFT MOD GW. have Telnet enabled by factory default. No password is set in the default configuration. Gateways with a serial number >2311xxxx have the Telnet interface disabled by factory default.
{
"affected": [],
"aliases": [
"CVE-2023-23451"
],
"database_specific": {
"cwe_ids": [
"CWE-306",
"CWE-477"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-04-19T23:15:06Z",
"severity": "CRITICAL"
},
"details": "The Flexi Classic and Flexi Soft Gateways SICK UE410-EN3 FLEXI ETHERNET GATEW., SICK UE410-EN1 FLEXI ETHERNET GATEW., SICK UE410-EN3S04 FLEXI ETHERNET GATEW., SICK UE410-EN4 FLEXI ETHERNET GATEW., SICK FX0-GENT00000 FLEXISOFT EIP GATEW., SICK FX0-GMOD00000 FLEXISOFT MOD GATEW., SICK FX0-GPNT00000 FLEXISOFT PNET GATEW., SICK FX0-GENT00030 FLEXISOFT EIP GATEW.V2, SICK FX0-GPNT00030 FLEXISOFT PNET GATEW.V2 and SICK FX0-GMOD00010 FLEXISOFT MOD GW. have Telnet enabled by factory default. No password is set in the default configuration. Gateways with a serial number \u003e2311xxxx have the Telnet interface disabled by factory default.",
"id": "GHSA-j4pp-rp58-2qhj",
"modified": "2024-04-04T03:36:30Z",
"published": "2023-04-20T00:30:43Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-23451"
},
{
"type": "WEB",
"url": "https://sick.com/psirt"
}
],
"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-J4R5-X8VX-WHV5
Vulnerability from github – Published: 2026-04-21 21:31 – Updated: 2026-04-21 21:31Vulnerability in the Oracle Identity Manager Connector product of Oracle Fusion Middleware (component: Core). The supported version that is affected is 12.2.1.4.0. Difficult to exploit vulnerability allows unauthenticated attacker with network access via HTTP to compromise Oracle Identity Manager Connector. Successful attacks of this vulnerability can result in unauthorized access to critical data or complete access to all Oracle Identity Manager Connector accessible data. CVSS 3.1 Base Score 5.9 (Confidentiality impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N).
{
"affected": [],
"aliases": [
"CVE-2026-34288"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-21T21:16:33Z",
"severity": "MODERATE"
},
"details": "Vulnerability in the Oracle Identity Manager Connector product of Oracle Fusion Middleware (component: Core). The supported version that is affected is 12.2.1.4.0. Difficult to exploit vulnerability allows unauthenticated attacker with network access via HTTP to compromise Oracle Identity Manager Connector. Successful attacks of this vulnerability can result in unauthorized access to critical data or complete access to all Oracle Identity Manager Connector accessible data. CVSS 3.1 Base Score 5.9 (Confidentiality impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N).",
"id": "GHSA-j4r5-x8vx-whv5",
"modified": "2026-04-21T21:31:26Z",
"published": "2026-04-21T21:31:26Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34288"
},
{
"type": "WEB",
"url": "https://www.oracle.com/security-alerts/cpuapr2026.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-J4XH-QHCF-RPXF
Vulnerability from github – Published: 2024-01-11 00:30 – Updated: 2024-01-11 00:30An attacker with network access to the affected PLC (CJ-series and CS-series PLCs, all versions) may use a network protocol to read and write files form the PLC internal memory and memory card.
{
"affected": [],
"aliases": [
"CVE-2022-45794"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-01-10T23:15:08Z",
"severity": "HIGH"
},
"details": "An attacker with network access to the affected PLC (CJ-series and CS-series PLCs, all versions) may use a network protocol to read and write files form the PLC internal memory and memory card.\n",
"id": "GHSA-j4xh-qhcf-rpxf",
"modified": "2024-01-11T00:30:26Z",
"published": "2024-01-11T00:30:26Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-45794"
},
{
"type": "WEB",
"url": "https://www.dragos.com/advisory/omron-plc-and-engineering-software-network-and-file-format-access"
},
{
"type": "WEB",
"url": "https://www.fa.omron.co.jp/product/security/assets/pdf/en/OMSR-2023-002_en.pdf"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-J4XP-CC3J-2W8R
Vulnerability from github – Published: 2022-05-24 16:55 – Updated: 2024-04-04 01:50A broken access control vulnerability found in Advan VD-1 firmware versions up to 230. An attacker can send a POST request to cgibin/ApkUpload.cgi to install arbitrary APK without any authentication.
{
"affected": [],
"aliases": [
"CVE-2019-13406"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-08-29T01:15:00Z",
"severity": "HIGH"
},
"details": "A broken access control vulnerability found in Advan VD-1 firmware versions up to 230. An attacker can send a POST request to cgibin/ApkUpload.cgi to install arbitrary APK without any authentication.",
"id": "GHSA-j4xp-cc3j-2w8r",
"modified": "2024-04-04T01:50:38Z",
"published": "2022-05-24T16:55:07Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-13406"
},
{
"type": "WEB",
"url": "https://gist.github.com/keniver/f5155b42eb278ec0273b83565b64235b#file-androvideo-advan-vd-1-multiple-vulnerabilities-md"
},
{
"type": "WEB",
"url": "https://tvn.twcert.org.tw/taiwanvn/TVN-201906007"
},
{
"type": "WEB",
"url": "http://surl.twcert.org.tw/hVut7"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
]
}
Mitigation
- 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
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
- 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
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
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.