CVE-2026-55538

CVE-2026-55538 is a high-severity missing authentication for critical function vulnerability in PraisonAI (pip), affecting versions < 4.6.58. It is fixed in 4.6.58.

Does this CVE actually affect you?

Kodem shows which CVEs are reachable and running in your applications, so you fix what's exploitable, not just what's listed.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Runtime intelligence, not another scanner.

Summary

PraisonAI: [Auth Bypass] praisonai serve agents --api-key is silently ignored, agent-invocation routes (POST /agents, POST /agents/{agent_name}) run unauthenticated

praisonai serve agents exposes HTTP routes that invoke registered agents. The CLI advertises --api-key with help text "API key for authentication", parses it, and forwards it into ServeHandler. But _create_agents_app() never reads config["api_key"] again and installs no auth dependency or middleware on its direct routes. The configured key is a no-op flag.

As a result, an unauthenticated network caller can invoke exposed agents (POST /agents and POST /agents/{agent_name}) even when the operator passed --api-key. Requests with no credentials, a wrong Authorization: Bearer, a wrong X-API-Key, or an empty bearer all reach agent.start().

The failure is made sharper by the fact that a working auth dependency already exists in the same module, praisonai.api.agent_invoke.verify_token guards every /api/v1/... route with Depends(verify_token) and is mounted into the very same app. The direct n8n-compat routes simply do not use it.

Technical Detail

Source-to-sink trace

1. CLI advertises and forwards --api-key:

# cli/commands/serve.py
@app.command("agents")
def serve_agents(..., api_key: Optional[str] = typer.Option(None, "--api-key", help="API key for authentication")):
    ...
    if api_key:
        args.extend(["--api-key", api_key])
    exit_code = handle_serve_command(args)

2. cmd_agents() parses api_key into the spec, and that is the last time it is touched:

# cli/features/serve.py, cmd_agents()
spec = { ..., "api_key": {"default": None} }
parsed = self._parse_args(args, spec)
app = self._create_agents_app(parsed)

A grep of the entire cli/features/serve.py for api_key returns only the two spec entries (cmd_agents line ~199 and cmd_unified line ~847). config["api_key"] is never read inside _create_agents_app() / _create_unified_app(); it is never compared, and no dependency is attached.

3. _create_agents_app() imports FastAPI, HTTPException, Request, no Depends, no Header, no auth middleware. Every HTTPException raised in the agents routes is 400/404/500 (validation / not-found / execution error); none is 401.

4. Sink, unauthenticated request reaches agent.start():

# cli/features/serve.py
@app.post("/agents/{agent_name}")          # n8n compatibility route
async def invoke_single_agent(agent_name: str, request: Request):
    body = await request.json()
    query = body.get("query", "") or body.get("message", "")
    ...
    agent = agent_invoke.get_agent(agent_name)
    result = await loop.run_in_executor(None, agent.start, query)   # no auth anywhere above
    return {"response": str(result)}
 
@app.post(path)                            # default path "/agents"
async def invoke_agents(request: Request, query_data: AgentQuery = None):
    ... agent.start(query) ...

The auth dependency exists, it just isn't applied here

_create_agents_app() mounts the agent_invoke router into the same app:

# cli/features/serve.py
if getattr(agent_invoke, 'FASTAPI_AVAILABLE', False) and hasattr(agent_invoke, 'router'):
    app.include_router(agent_invoke.router)

That router properly authenticates every sensitive route:

# api/agent_invoke.py
CALL_SERVER_TOKEN = os.getenv('CALL_SERVER_TOKEN')
async def verify_token(request, authorization=Header(None)) -> None:
    ...
    if token != CALL_SERVER_TOKEN:
        raise HTTPException(status_code=401, detail="Unauthorized")
 
@router.get("/api/v1/agents")
async def list_agents(_: None = Depends(verify_token)): ...   # and register/unregister/info all use it

So in the same process GET /api/v1/agents returns 401 without a token, while POST /agents/{agent_name} returns 200. Note also that verify_token reads the CALL_SERVER_TOKEN env var, not the CLI --api-key, so the CLI option feeds no auth path at all.

Trigger conditions

praisonai serve agents --file agents.yaml --host 0.0.0.0 --port 8765 --api-key expected-secret
POST /agents/{agent_name}   body {"query":"..."}   with no / wrong / empty credentials

Proof of Concept

Built the real _create_agents_app() and exercised it over HTTP via FastAPI TestClient. Only praisonaiagents.Agent is stubbed (.start() returns EXEC:<query>), so no real LLM/credentials. CALL_SERVER_TOKEN=expected-secret was set so the sibling /api/v1 router is genuinely armed, making the contrast explicit.

Operator started with: --api-key expected-secret  (CALL_SERVER_TOKEN also set)
 
== Sibling /api/v1 route WITH Depends(verify_token) ==
  GET /api/v1/agents [no creds    ] -> HTTP 401
  GET /api/v1/agents [wrong bearer] -> HTTP 401
 
== Direct agent-invocation route (the bug) ==
  POST /agents/owned [no creds      ] -> HTTP 200  {'response': 'EXEC:hello'}
  POST /agents/owned [wrong bearer  ] -> HTTP 200  {'response': 'EXEC:hello'}
  POST /agents/owned [wrong x-api-key] -> HTTP 200  {'response': 'EXEC:hello'}
  POST /agents/owned [empty bearer  ] -> HTTP 200  {'response': 'EXEC:hello'}
  POST /agents       [no creds      ] -> HTTP 200  {'response': 'EXEC:hi'}

The auth mechanism works for /api/v1 (401) and is entirely absent on the direct /agents routes (200), despite --api-key being configured.

Equivalent HTTP trigger in a fully installed environment

praisonai serve agents --file agents.yaml --host 0.0.0.0 --port 8765 --api-key expected-secret
curl -sS -X POST http://TARGET:8765/agents/owned \
  -H 'Content-Type: application/json' --data-binary '{"query":"hello"}'
# -> 200 {"response":"..."}  (expected: 401 Unauthorized)

Suggested Mitigation

  • When config["api_key"] is set, build a shared auth dependency and attach it to every agent-invocation / state-changing route in _create_agents_app() and _create_unified_app() (dependencies=[Depends(verify)]).
  • Reuse / unify with the existing verify_token so the direct /agents routes and the /api/v1 routes share one mechanism, and wire the CLI --api-key into that mechanism (today it feeds nothing; verify_token reads CALL_SERVER_TOKEN).
  • Use constant-time comparison (hmac.compare_digest); verify_token currently uses !=.
  • Update discovery metadata from auth_modes=["none"] to ["api-key","bearer"] for protected endpoints.
  • Regression tests next to tests/unit/test_serve_unified.py: _create_agents_app({"api_key":"secret",...})POST /agents/{name} with no creds / wrong Authorization / wrong X-API-Key returns 401; correct key succeeds.
import hmac
from fastapi import Header, HTTPException, Depends
 
def _auth_dependency(expected_key: str):
    async def verify(authorization: str | None = Header(None),
                     x_api_key: str | None = Header(None, alias="X-API-Key")):
        token = x_api_key
        if authorization and authorization.startswith("Bearer "):
            token = authorization[7:]
        if not token or not hmac.compare_digest(token, expected_key):
            raise HTTPException(status_code=401, detail="Unauthorized")
    return Depends(verify)

Impact

  • Direct primitive: unauthenticated agent invocation despite a configured API key.
  • Misleading control (aggravating): because the CLI advertises --api-key as authentication, operators may deliberately expose the service (e.g. --host 0.0.0.0, reverse proxy, n8n integration) believing it is protected, increasing the real-world likelihood of exposure.
  • Downstream: exposed agents commonly hold LLM provider credentials, RAG/memory, browser/search, MCP, or shell/file tools; the bypass lets an attacker drive those capabilities. Baseline impact is unauthorized LLM cost + access to agent responses.

A critical operation is accessible without requiring any authentication. Typical impact: any user can invoke the privileged function.

CVE-2026-55538 has a CVSS score of 7.3 (High). The vector is network-reachable, no privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (4.6.58); upgrading removes the vulnerable code path.

Affected versions

PraisonAI (< 4.6.58)

Security releases

PraisonAI → 4.6.58 (pip)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

Already deployed Kodem?

See it in your environmentNew to Kodem? Get a demo →

Remediation advice

Upgrade PraisonAI to 4.6.58 or later to resolve this vulnerability.

Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.

Frequently Asked Questions

  1. What is CVE-2026-55538? CVE-2026-55538 is a high-severity missing authentication for critical function vulnerability in PraisonAI (pip), affecting versions < 4.6.58. It is fixed in 4.6.58. A critical operation is accessible without requiring any authentication.
  2. How severe is CVE-2026-55538? CVE-2026-55538 has a CVSS score of 7.3 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
  3. Which versions of PraisonAI are affected by CVE-2026-55538? PraisonAI (pip) versions < 4.6.58 is affected.
  4. Is there a fix for CVE-2026-55538? Yes. CVE-2026-55538 is fixed in 4.6.58. Upgrade to this version or later.
  5. Is CVE-2026-55538 exploitable, and should I be worried? Whether CVE-2026-55538 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  6. What actually determines whether CVE-2026-55538 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  7. How do I fix CVE-2026-55538? Upgrade PraisonAI to 4.6.58 or later.

Stop the waste.
Protect your environment with Kodem.