PT-2026-59541 · Pypi · Praisonai
Published
2026-07-13
·
Updated
2026-07-13
CVSS v3.1
7.3
High
| Vector | AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L |
Summary
PraisonAI ships a legacy Flask API server with authentication disabled by default. When that server is used, any caller that can reach it can access
/agents and trigger the configured agents.yaml workflow through /chat without providing a token.Details
The vulnerable server is the shipped
src/praisonai/api server.py entrypoint.AUTH ENABLED = FalseandAUTH TOKEN = Noneare hard-coded at [[src/praisonai/api server.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/api server.py:15)](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/api server.py:15).check auth()returnsTruewhenever authentication is disabled, so both protected routes fail open by design at [[src/praisonai/api server.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/api server.py:18)](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/api server.py:18).POST /chatonly checks that the request JSON contains amessagekey and then runsPraisonAI(agent file="agents.yaml").run()at [[src/praisonai/api server.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/api server.py:31)](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/api server.py:31).GET /agentsis guarded by the same no-op authentication check and returns agent metadata at [[src/praisonai/api server.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/api server.py:55)](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/[src/praisonai/api server.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/api server.py:66):55).- When launched directly, the same script binds to
0.0.0.0:8080at [src/praisonai/api server.py](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/api server.py:66).
The deploy subsystem keeps the same insecure authentication default:
APIConfigdefaultsauth enabledtoFalsein [src/praisonai/praisonai/deploy/models.py](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/deploy/models.py:23).- The generated sample API deployment YAML recommends
host: 0.0.0.0together withauth enabled: falsein [src/praisonai/praisonai/deploy/schema.py](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/deploy/schema.py:108).
For scope clarity: the newer
serve agents command is safer by default, because it binds to 127.0.0.1 and supports --api-key in [src/praisonai/praisonai/cli/commands/serve.py](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/cli/commands/serve.py:155). This report is about the shipped legacy API server and the generated/sample API deployment path above.Version scope:
v2.5.6already ships the samesrc/praisonai/api server.pyimplementation.- The current PyPI release on May 1, 2026 is
4.6.33, and it still ships the same unauthenticated server logic.
PoC
The following route-level reproduction was verified locally and proves that the shipped
api server.py exposes /agents and /chat without authentication.- From the repository root, create a throwaway environment with the server's direct Flask dependencies:
bash
python3 -m venv /tmp/praisonai-ghsa-venv
/tmp/praisonai-ghsa-venv/bin/pip install flask flask-cors- Execute the shipped
src/praisonai/api server.pyunder a minimal stub forpraisonai.PraisonAIso only the server auth logic is exercised:
bash
/tmp/praisonai-ghsa-venv/bin/python - <<'PY'
import importlib.util
import pathlib
import sys
import types
stub = types.ModuleType("praisonai")
class DummyPraisonAI:
def init (self, agent file="agents.yaml"):
self.agent file = agent file
def run(self):
return {"ran": True, "agent file": self.agent file}
stub.PraisonAI = DummyPraisonAI
sys.modules["praisonai"] = stub
path = pathlib.Path("src/praisonai/api server.py").resolve()
spec = importlib.util.spec from file location("api server local", path)
mod = importlib.util.module from spec(spec)
spec.loader.exec module(mod)
client = mod.app.test client()
print(client.get("/agents").status code, client.get("/agents").get data(as text=True))
print(client.post("/chat", json={"message": "hello"}).status code, client.post("/chat", json={"message": "hello"}).get data(as text=True))
PY- Observed result:
text
200 {"agent file":"agents.yaml","agents":["default"]}
200 {"response":{"agent file":"agents.yaml","ran":true},"status":"success"}Both endpoints succeed without any
Authorization header.Impact
Any reachable caller can invoke the legacy API server's protected functionality without a token.
At minimum, this allows:
- unauthenticated enumeration of the configured agent file through
/agents - unauthenticated triggering of the locally configured
agents.yamlworkflow through/chat - repeated consumption of model/API quota and any other side effects performed by that workflow
- exposure of whatever result
PraisonAI.run()returns to the unauthenticated caller
This is not the same as arbitrary prompt injection by itself, because the current
/chat handler ignores the submitted message value and simply runs the configured workflow. The impact therefore depends on what the operator's agents.yaml is allowed to do, but the authentication bypass is unconditional in the shipped legacy server.Fix
Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Praisonai