CVE-2026-57127
praisonai: recipe serve auth middleware silently disables itself when no secret is set
PraisonAI is a multi-agent teams system. Prior to 4.6.58, recipe serve installs APIKeyAuthMiddleware or JWTAuthMiddleware when an operator selects api-key or JWT authentication, but each middleware forwards requests when PRAISONAI_API_KEY or PRAISONAI_JWT_SECRET and the corresponding recipe value are absent. Unauthenticated clients can then reach recipe execution, input, and output surfaces and may trigger connected tools despite the operator explicitly enabling authentication. This issue is fixed in 4.6.58.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
9.8
praisonai: recipe serve auth middleware silently disables itself when no secret is set
PraisonAI is a multi-agent teams system. Prior to 4.6.58, recipe serve installs APIKeyAuthMiddleware or JWTAuthMiddleware when an operator selects api-key or JWT authentication, but each middleware forwards requests when PRAISONAI_API_KEY or PRAISONAI_JWT_SECRET and the corresponding recipe value are absent. Unauthenticated clients can then reach recipe execution, input, and output surfaces and may trigger connected tools despite the operator explicitly enabling authentication. This issue is fixed in 4.6.58.
- Record
CVE-2026-57127- CVSS 3.1
- 9.8 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-306, CWE-1188
- Updated
- 2026-11-02
EUVDEUVD-2026-77615
9.8
PraisonAI is a multi-agent teams system. Prior to 4.6.58, recipe serve installs APIKeyAuthMiddleware or JWTAuthMiddleware when an operator selects api-key or JWT authentication, but each middleware forwards requests when PRAISONAI_API_KEY or PRAISONAI_JWT_SECRET and the corresponding recipe value are absent. Unauthenticated clients can then reach recipe execution, input, and output surfaces and may trigger connected tools despite the operator explicitly enabling authentication. This issue is fixed in 4.6.58.
- Record
EUVD-2026-77615- CVSS 3.1
- 9.8 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-j4hj-7hfh-g2f4
9.8
praisonai: recipe serve auth middleware silently disables itself when no secret is set
praisonai: recipe serve authentication middleware silently disables itself when no secret is set
Researcher: Kai Aizen — SnailSploit (@SnailSploit), Adversarial & Offensive Security Research Target: https://github.com/MervinPraison/PraisonAI
Package: praisonai on PyPI
Version tested: 4.6.48.
File: praisonai/recipe/serve.py (sha256 491bf8f29e399418260810ba4bf0f6802c6e4aa675628e2be68a9726c15d9b23).
TL;DR
praisonai/recipe/serve.py:312-410 defines two auth middlewares (APIKeyAuthMiddleware, JWTAuthMiddleware). Both contain the same "fail open when the secret is unset" branch at the top of their dispatch:
async def dispatch(self, request, call_next):
if request.url.path == "/health":
return await call_next(request)
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)
...
async def dispatch(self, request, call_next):
if request.url.path == "/health":
return await call_next(request)
secret = jwt_secret or os.environ.get("PRAISONAI_JWT_SECRET")
if not secret:
return await call_next(request)
...
The realistic mis-deploy:
- operator sets
auth: api-key(orauth: jwt) in their recipe YAML, expecting that line alone to enable auth, - operator does not set the corresponding
api_key:/jwt_secret:value in the same YAML, AND - operator does not export
PRAISONAI_API_KEY/PRAISONAI_JWT_SECRETin the environment.
The middleware silently treats every request as authenticated and forwards it to the recipe-execution route.
Combined with the praisonai jobs API having zero auth (a separate finding), operators who paid attention to "I have to set auth: api-key to lock this down" still don't get auth on the recipe-serve surface unless they also remember the secret.
Root cause
Expected behavior, after setting `auth: api-key` in the recipe YAML:
"Now my recipe endpoints require an X-API-Key header."
Actual behavior (serve.py:325-333):
- middleware reads `expected_key = api_key or
os.environ.get("PRAISONAI_API_KEY")`
- if `expected_key` is None (neither YAML nor env supplied
one), middleware logs nothing and forwards the request.
- operator's recipe routes accept the request as if it were
authenticated. request.state.user is unset.
Impact:
The middleware's documented job is "validate the API key
against the configured value". The configured-value-is-None
case is exactly the case the middleware should fail closed
on — operator has signalled they want auth. Failing open
silently turns a documented authentication into a runtime
no-op.
Empirical verification
poc/poc.py:
- Imports the installed praisonai 4.6.48
praisonai.recipe.servemodule (sha256491bf8f29e399418260810ba4bf0f6802c6e4aa675628e2be68a9726c15d9b23). - Clears
PRAISONAI_API_KEY/PRAISONAI_JWT_SECRETenv vars to simulate the mis-deploy. - Calls
serve.create_auth_middleware('api-key', api_key=None, jwt_secret=None)and instantiates the returned middleware. - Builds a Starlette
Requestfor/runs(the recipe-execution path) with empty headers — noX-API-Key, noAuthorization. await middleware.dispatch(request, fake_call_next)returns the sentinel'REACHED-DOWNSTREAM (path=/runs)'from the fakecall_next— proving the middleware passed the request through without authenticating.- Repeats the test for
auth_type='jwt'— same bypass on the JWT path.
Run log (poc/run-log.txt) summary:
[2] auth_type='api-key', no api_key / no PRAISONAI_API_KEY env
middleware.dispatch -> 'REACHED-DOWNSTREAM (path=/runs)'
[3] auth_type='jwt', no jwt_secret / no PRAISONAI_JWT_SECRET env
middleware.dispatch -> 'REACHED-DOWNSTREAM (path=/runs)'
APIKeyAuthMiddleware allowed the request…
- Record
GHSA-j4hj-7hfh-g2f4- CVSS 3.1
- 9.8 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-306, CWE-1188
- Updated
- 2026-11-02
NVD
9.8
PraisonAI is a multi-agent teams system. Prior to 4.6.58, recipe serve installs APIKeyAuthMiddleware or JWTAuthMiddleware when an operator selects api-key or JWT authentication, but each middleware forwards requests when PRAISONAI_API_KEY or PRAISONAI_JWT_SECRET and the corresponding recipe value are absent. Unauthenticated clients can then reach recipe execution, input, and output surfaces and may trigger connected tools despite the operator explicitly enabling authentication. This issue is fixed in 4.6.58.
- Record
CVE-2026-57127- CVSS 3.1
- 9.8 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-306, CWE-1188
- Updated
- 2026-11-02
OSV
9.8
praisonai: recipe serve auth middleware silently disables itself when no secret is set
PraisonAI is a multi-agent teams system. Prior to 4.6.58, recipe serve installs APIKeyAuthMiddleware or JWTAuthMiddleware when an operator selects api-key or JWT authentication, but each middleware forwards requests when PRAISONAI_API_KEY or PRAISONAI_JWT_SECRET and the corresponding recipe value are absent. Unauthenticated clients can then reach recipe execution, input, and output surfaces and may trigger connected tools despite the operator explicitly enabling authentication. This issue is fixed in 4.6.58.
- Record
CVE-2026-57127- CVSS 3.1
- 9.8 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-1188, CWE-306
- Updated
- 2026-11-02
OSVGHSA-j4hj-7hfh-g2f4
9.8
praisonai: recipe serve auth middleware silently disables itself when no secret is set
praisonai: recipe serve authentication middleware silently disables itself when no secret is set
Researcher: Kai Aizen — SnailSploit (@SnailSploit), Adversarial & Offensive Security Research Target: https://github.com/MervinPraison/PraisonAI
Package: praisonai on PyPI
Version tested: 4.6.48.
File: praisonai/recipe/serve.py (sha256 491bf8f29e399418260810ba4bf0f6802c6e4aa675628e2be68a9726c15d9b23).
TL;DR
praisonai/recipe/serve.py:312-410 defines two auth middlewares (APIKeyAuthMiddleware, JWTAuthMiddleware). Both contain the same "fail open when the secret is unset" branch at the top of their dispatch:
async def dispatch(self, request, call_next):
if request.url.path == "/health":
return await call_next(request)
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)
...
async def dispatch(self, request, call_next):
if request.url.path == "/health":
return await call_next(request)
secret = jwt_secret or os.environ.get("PRAISONAI_JWT_SECRET")
if not secret:
return await call_next(request)
...
The realistic mis-deploy:
- operator sets
auth: api-key(orauth: jwt) in their recipe YAML, expecting that line alone to enable auth, - operator does not set the corresponding
api_key:/jwt_secret:value in the same YAML, AND - operator does not export
PRAISONAI_API_KEY/PRAISONAI_JWT_SECRETin the environment.
The middleware silently treats every request as authenticated and forwards it to the recipe-execution route.
Combined with the praisonai jobs API having zero auth (a separate finding), operators who paid attention to "I have to set auth: api-key to lock this down" still don't get auth on the recipe-serve surface unless they also remember the secret.
Root cause
Expected behavior, after setting `auth: api-key` in the recipe YAML:
"Now my recipe endpoints require an X-API-Key header."
Actual behavior (serve.py:325-333):
- middleware reads `expected_key = api_key or
os.environ.get("PRAISONAI_API_KEY")`
- if `expected_key` is None (neither YAML nor env supplied
one), middleware logs nothing and forwards the request.
- operator's recipe routes accept the request as if it were
authenticated. request.state.user is unset.
Impact:
The middleware's documented job is "validate the API key
against the configured value". The configured-value-is-None
case is exactly the case the middleware should fail closed
on — operator has signalled they want auth. Failing open
silently turns a documented authentication into a runtime
no-op.
Empirical verification
poc/poc.py:
- Imports the installed praisonai 4.6.48
praisonai.recipe.servemodule (sha256491bf8f29e399418260810ba4bf0f6802c6e4aa675628e2be68a9726c15d9b23). - Clears
PRAISONAI_API_KEY/PRAISONAI_JWT_SECRETenv vars to simulate the mis-deploy. - Calls
serve.create_auth_middleware('api-key', api_key=None, jwt_secret=None)and instantiates the returned middleware. - Builds a Starlette
Requestfor/runs(the recipe-execution path) with empty headers — noX-API-Key, noAuthorization. await middleware.dispatch(request, fake_call_next)returns the sentinel'REACHED-DOWNSTREAM (path=/runs)'from the fakecall_next— proving the middleware passed the request through without authenticating.- Repeats the test for
auth_type='jwt'— same bypass on the JWT path.
Run log (poc/run-log.txt) summary:
[2] auth_type='api-key', no api_key / no PRAISONAI_API_KEY env
middleware.dispatch -> 'REACHED-DOWNSTREAM (path=/runs)'
[3] auth_type='jwt', no jwt_secret / no PRAISONAI_JWT_SECRET env
middleware.dispatch -> 'REACHED-DOWNSTREAM (path=/runs)'
APIKeyAuthMiddleware allowed the request…
- Record
GHSA-j4hj-7hfh-g2f4- CVSS 3.1
- 9.8 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-1188, CWE-306
- Updated
- 2026-11-02
OSVPYSEC-2026-3513
9.8
praisonai: recipe serve auth middleware silently disables itself when no secret is set
praisonai: recipe serve authentication middleware silently disables itself when no secret is set
Researcher: Kai Aizen — SnailSploit (@SnailSploit), Adversarial & Offensive Security Research Target: https://github.com/MervinPraison/PraisonAI
Package: praisonai on PyPI
Version tested: 4.6.48.
File: praisonai/recipe/serve.py (sha256 491bf8f29e399418260810ba4bf0f6802c6e4aa675628e2be68a9726c15d9b23).
TL;DR
praisonai/recipe/serve.py:312-410 defines two auth middlewares (APIKeyAuthMiddleware, JWTAuthMiddleware). Both contain the same "fail open when the secret is unset" branch at the top of their dispatch:
async def dispatch(self, request, call_next):
if request.url.path == "/health":
return await call_next(request)
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)
...
async def dispatch(self, request, call_next):
if request.url.path == "/health":
return await call_next(request)
secret = jwt_secret or os.environ.get("PRAISONAI_JWT_SECRET")
if not secret:
return await call_next(request)
...
The realistic mis-deploy:
- operator sets
auth: api-key(orauth: jwt) in their recipe YAML, expecting that line alone to enable auth, - operator does not set the corresponding
api_key:/jwt_secret:value in the same YAML, AND - operator does not export
PRAISONAI_API_KEY/PRAISONAI_JWT_SECRETin the environment.
The middleware silently treats every request as authenticated and forwards it to the recipe-execution route.
Combined with the praisonai jobs API having zero auth (a separate finding), operators who paid attention to "I have to set auth: api-key to lock this down" still don't get auth on the recipe-serve surface unless they also remember the secret.
Root cause
Expected behavior, after setting `auth: api-key` in the recipe YAML:
"Now my recipe endpoints require an X-API-Key header."
Actual behavior (serve.py:325-333):
- middleware reads `expected_key = api_key or
os.environ.get("PRAISONAI_API_KEY")`
- if `expected_key` is None (neither YAML nor env supplied
one), middleware logs nothing and forwards the request.
- operator's recipe routes accept the request as if it were
authenticated. request.state.user is unset.
Impact:
The middleware's documented job is "validate the API key
against the configured value". The configured-value-is-None
case is exactly the case the middleware should fail closed
on — operator has signalled they want auth. Failing open
silently turns a documented authentication into a runtime
no-op.
Empirical verification
poc/poc.py:
- Imports the installed praisonai 4.6.48
praisonai.recipe.servemodule (sha256491bf8f29e399418260810ba4bf0f6802c6e4aa675628e2be68a9726c15d9b23). - Clears
PRAISONAI_API_KEY/PRAISONAI_JWT_SECRETenv vars to simulate the mis-deploy. - Calls
serve.create_auth_middleware('api-key', api_key=None, jwt_secret=None)and instantiates the returned middleware. - Builds a Starlette
Requestfor/runs(the recipe-execution path) with empty headers — noX-API-Key, noAuthorization. await middleware.dispatch(request, fake_call_next)returns the sentinel'REACHED-DOWNSTREAM (path=/runs)'from the fakecall_next— proving the middleware passed the request through without authenticating.- Repeats the test for
auth_type='jwt'— same bypass on the JWT path.
Run log (poc/run-log.txt) summary:
[2] auth_type='api-key', no api_key / no PRAISONAI_API_KEY env
middleware.dispatch -> 'REACHED-DOWNSTREAM (path=/runs)'
[3] auth_type='jwt', no jwt_secret / no PRAISONAI_JWT_SECRET env
middleware.dispatch -> 'REACHED-DOWNSTREAM (path=/runs)'
APIKeyAuthMiddleware allowed the request…
- Record
PYSEC-2026-3513- CVSS 3.1
- 9.8 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
praisonaiPyPI |
through 4.6.48 | 4.6.59 |
praisonaiPyPI |
before 4.6.59, plus listed versions 0.0.10.0.100.0.110.0.120.0.13 Show 45 moreShow less0.0.140.0.150.0.160.0.170.0.180.0.190.0.20.0.200.0.210.0.220.0.230.0.240.0.250.0.260.0.270.0.280.0.290.0.30.0.300.0.310.0.320.0.330.0.340.0.350.0.360.0.370.0.380.0.390.0.40.0.400.0.410.0.420.0.430.0.440.0.450.0.460.0.470.0.480.0.490.0.50.0.500.0.520.0.530.0.540.0.55 |
4.6.59 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-57127 is a critical vulnerability (CVSS 9.8) in Mervinpraison Praisonai, published June 18, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.90%, the 59th percentile. Fixed in praisonai 4.6.59.
References
github.com/MervinPraison/PraisonAI/security/advisories/GHSA-j4hj-7hfh-g2f4
github.com/MervinPraison/PraisonAI/commit/2f9677abb2ea68eab864ee8b6a828fd0141612e1
github.com/MervinPraison/PraisonAI/releases/tag/v4.6.58
github.com/advisories/GHSA-j4hj-7hfh-g2f4
github.com/CVEProject/cvelistV5/tree/main/cves/2026/57xxx/CVE-2026-57127.json
nvd.nist.gov/vuln/detail/CVE-2026-57127
github.com/MervinPraison/PraisonAI
pypi.org/project/praisonai
Left out here: 699 versions and the rest of 3 source descriptions. The JSON record has them.