Описание
PraisonAI: [Auth Bypass] praisonai serve agents --api-key is silently ignored — agent-invocation routes (POST /agents, POST /agents/{agent_name}) run unauthenticated
Summary
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:
2. cmd_agents() parses api_key into the spec — and that is the last time it is touched:
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():
The auth dependency exists — it just isn't applied here
_create_agents_app() mounts the agent_invoke router into the same app:
That router properly authenticates every sensitive route:
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
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.
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
Impact
- Direct primitive: unauthenticated agent invocation despite a configured API key.
- Misleading control (aggravating): because the CLI advertises
--api-keyas 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.
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_tokenso the direct/agentsroutes and the/api/v1routes share one mechanism, and wire the CLI--api-keyinto that mechanism (today it feeds nothing;verify_tokenreadsCALL_SERVER_TOKEN). - Use constant-time comparison (
hmac.compare_digest);verify_tokencurrently 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 / wrongAuthorization/ wrongX-API-Keyreturns401; correct key succeeds.
Пакеты
PraisonAI
< 4.6.58
4.6.58
Связанные уязвимости
PraisonAI is a multi-agent teams system. Prior to praisonai 4.6.51, praisonai serve agents parses config["api_key"] but _create_agents_app() does not authenticate POST /agents or POST /agents/{agent_name}. Missing or incorrect bearer and X-API-Key values still reach agent execution. This issue is fixed in version 4.6.58.