CVE-2026-56836
PraisonAI recipe serve Typer command bypasses the non-localhost authentication guard
PraisonAI is a multi-agent teams system. From version 4.5.112 to before version 4.6.59, PraisonAI's installed console entrypoint is Typer-first. In current releases, the recipe command is registered in the Typer app and praisonai recipe serve dispatches to the deprecated Typer command in src/praisonai/praisonai/cli/commands/recipe.py. That Typer command can start the Recipe HTTP server on a non-localhost interface with no authentication. It prints a deprecation warning, and then launches the server. Because config.auth is absent, create_app() does not attach the API-key or JWT middleware. Unauthenticated requests can then reach the recipe API and, when enabled, /admin/reload. This issue has been patched in version 4.6.59.
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
- Low
- Integrity
- High
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
8.2
PraisonAI recipe serve Typer command bypasses the non-localhost authentication guard
PraisonAI is a multi-agent teams system. From version 4.5.112 to before version 4.6.59, PraisonAI's installed console entrypoint is Typer-first. In current releases, the recipe command is registered in the Typer app and praisonai recipe serve dispatches to the deprecated Typer command in src/praisonai/praisonai/cli/commands/recipe.py. That Typer command can start the Recipe HTTP server on a non-localhost interface with no authentication. It prints a deprecation warning, and then launches the server. Because config.auth is absent, create_app() does not attach the API-key or JWT middleware. Unauthenticated requests can then reach the recipe API and, when enabled, /admin/reload. This issue has been patched in version 4.6.59.
- Record
CVE-2026-56836- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N - Weakness
- CWE-287, CWE-306, CWE-862
- Updated
- 2026-11-02
EUVDEUVD-2026-108877
8.2
PraisonAI is a multi-agent teams system. From version 4.5.112 to before version 4.6.59, PraisonAI's installed console entrypoint is Typer-first. In current releases, the recipe command is registered in the Typer app and praisonai recipe serve dispatches to the deprecated Typer command in src/praisonai/praisonai/cli/commands/recipe.py. That Typer command can start the Recipe HTTP server on a non-localhost interface with no authentication. It prints a deprecation warning, and then launches the server. Because config.auth is absent, create_app() does not attach the API-key or JWT middleware. Unauthenticated requests can then reach the recipe API and, when enabled, /admin/reload. This issue has been patched in version 4.6.59.
- Record
EUVD-2026-108877- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-5qw8-f2g9-ff29
8.2
PraisonAI recipe serve Typer command bypasses the non-localhost authentication guard
PraisonAI recipe serve Typer command bypasses the non-localhost authentication guard
Summary
PraisonAI's installed console entrypoint is Typer-first. In current releases,
the recipe command is registered in the Typer app and
praisonai recipe serve dispatches to the deprecated Typer command in
src/praisonai/praisonai/cli/commands/recipe.py.
That Typer command can start the Recipe HTTP server on a non-localhost interface with no authentication:
praisonai recipe serve --host 0.0.0.0 --admin
It prints a deprecation warning, then launches the server with:
{
"host": "0.0.0.0",
"config": {
"cors_origins": "*",
"enable_admin": true
}
}
Because config.auth is absent, create_app() does not attach the API-key or
JWT middleware. Unauthenticated requests can then reach the recipe API and, when
enabled, /admin/reload.
This is an incomplete hardening / sibling-callsite issue. The legacy feature
handler in src/praisonai/praisonai/cli/features/recipe.py rejects the same
non-localhost/no-auth combination, and current create_auth_middleware() now
fails closed if API-key/JWT auth is selected without a secret. The installed
Typer command bypasses both expectations by never requiring or setting auth.
Affected product
- Repository:
MervinPraison/PraisonAI - Package:
praisonai - Component:
src/praisonai/praisonai/__main__.pysrc/praisonai/praisonai/cli/app.pysrc/praisonai/praisonai/cli/commands/recipe.pysrc/praisonai/praisonai/cli/features/recipe.pysrc/praisonai/praisonai/recipe/serve.py
Confirmed affected:
v4.6.58 1ad58ca02975ff1398efeda694ea2ab78f20cf3e
v4.6.57 e90d92231853161ad931f3498da57651a9f8b528
v4.6.56 d3c4a2afadfbf3a3e172e460e607ba4efad263a6
v4.6.34 e5928449f73f66cc8af1de61621aa974ab255133
v4.6.33 dfbb8d78ec7e8dc7118bc722ab1b2524bc98ddab
v4.6.10 4b1b17b963cbd0625e41394a30168c95b26429b2
v4.5.128 b4e3a8a84ade44ac3dd9102b792cdb4311a95937
v4.5.112 bfe3d94bad6db92fc2927c2e3c081ae8303e209e
Suggested affected range: praisonai >= 4.5.112, <= 4.6.58.
The lower bound is conservative and based on sampled tags. Maintainers should confirm the exact introduction point before publishing a final range.
Root cause
The installed entrypoint routes registered Typer commands before falling back to the legacy dispatcher:
if first_cmd in _get_typer_commands():
_run_typer(argv)
else:
_run_legacy(argv)
cli/app.py registers commands.recipe as the recipe Typer command:
from .commands.recipe import app as recipe_app
...
app.add_typer(recipe_app, name="recipe", help="Recipe management")
The deprecated Typer recipe serve implementation accepts a remote host,
defaults CORS to *, and only enables authentication when --api-key is
explicitly provided:
host: str = typer.Option("127.0.0.1", "--host", "-h", ...)
api_key: str = typer.Option(None, "--api-key", ...)
cors: str = typer.Option("*", "--cors", ...)
admin: bool = typer.Option(False, "--admin", ...)
...
serve_config = {}
...
if api_key:
serve_config["api_key"] = api_key
serve_config["auth"] = "api-key"
if cors:
serve_config["cors_origins"] = cors
if admin:
serve_config["enable_admin"] = True
...
serve(host=host, port=port, reload=reload, config=serve_config, workers=workers)
There is no equivalent to the hardened non-localhost guard in the legacy feature handler:
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
The Recipe server only installs auth middleware when config["auth"] is set:
auth_type = config.get("auth")
if auth_type and auth_type != "none":
auth_middleware = create_auth_middleware(...)
if auth_middleware:
middleware.append(Middleware(auth_middleware))
On current v4.6.58, the…
- Record
GHSA-5qw8-f2g9-ff29- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N - Weakness
- CWE-287, CWE-306, CWE-862
- Updated
- 2026-11-02
NVD
8.2
PraisonAI is a multi-agent teams system. From version 4.5.112 to before version 4.6.59, PraisonAI's installed console entrypoint is Typer-first. In current releases, the recipe command is registered in the Typer app and praisonai recipe serve dispatches to the deprecated Typer command in src/praisonai/praisonai/cli/commands/recipe.py. That Typer command can start the Recipe HTTP server on a non-localhost interface with no authentication. It prints a deprecation warning, and then launches the server. Because config.auth is absent, create_app() does not attach the API-key or JWT middleware. Unauthenticated requests can then reach the recipe API and, when enabled, /admin/reload. This issue has been patched in version 4.6.59.
- Record
CVE-2026-56836- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N - Weakness
- CWE-287, CWE-306, CWE-862
- Updated
- 2026-11-02
OSV
8.2
PraisonAI recipe serve Typer command bypasses the non-localhost authentication guard
PraisonAI is a multi-agent teams system. From version 4.5.112 to before version 4.6.59, PraisonAI's installed console entrypoint is Typer-first. In current releases, the recipe command is registered in the Typer app and praisonai recipe serve dispatches to the deprecated Typer command in src/praisonai/praisonai/cli/commands/recipe.py. That Typer command can start the Recipe HTTP server on a non-localhost interface with no authentication. It prints a deprecation warning, and then launches the server. Because config.auth is absent, create_app() does not attach the API-key or JWT middleware. Unauthenticated requests can then reach the recipe API and, when enabled, /admin/reload. This issue has been patched in version 4.6.59.
- Record
CVE-2026-56836- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N - Weakness
- CWE-287, CWE-306, CWE-862
- Updated
- 2026-11-02
OSVGHSA-5qw8-f2g9-ff29
8.2
PraisonAI recipe serve Typer command bypasses the non-localhost authentication guard
PraisonAI recipe serve Typer command bypasses the non-localhost authentication guard
Summary
PraisonAI's installed console entrypoint is Typer-first. In current releases,
the recipe command is registered in the Typer app and
praisonai recipe serve dispatches to the deprecated Typer command in
src/praisonai/praisonai/cli/commands/recipe.py.
That Typer command can start the Recipe HTTP server on a non-localhost interface with no authentication:
praisonai recipe serve --host 0.0.0.0 --admin
It prints a deprecation warning, then launches the server with:
{
"host": "0.0.0.0",
"config": {
"cors_origins": "*",
"enable_admin": true
}
}
Because config.auth is absent, create_app() does not attach the API-key or
JWT middleware. Unauthenticated requests can then reach the recipe API and, when
enabled, /admin/reload.
This is an incomplete hardening / sibling-callsite issue. The legacy feature
handler in src/praisonai/praisonai/cli/features/recipe.py rejects the same
non-localhost/no-auth combination, and current create_auth_middleware() now
fails closed if API-key/JWT auth is selected without a secret. The installed
Typer command bypasses both expectations by never requiring or setting auth.
Affected product
- Repository:
MervinPraison/PraisonAI - Package:
praisonai - Component:
src/praisonai/praisonai/__main__.pysrc/praisonai/praisonai/cli/app.pysrc/praisonai/praisonai/cli/commands/recipe.pysrc/praisonai/praisonai/cli/features/recipe.pysrc/praisonai/praisonai/recipe/serve.py
Confirmed affected:
v4.6.58 1ad58ca02975ff1398efeda694ea2ab78f20cf3e
v4.6.57 e90d92231853161ad931f3498da57651a9f8b528
v4.6.56 d3c4a2afadfbf3a3e172e460e607ba4efad263a6
v4.6.34 e5928449f73f66cc8af1de61621aa974ab255133
v4.6.33 dfbb8d78ec7e8dc7118bc722ab1b2524bc98ddab
v4.6.10 4b1b17b963cbd0625e41394a30168c95b26429b2
v4.5.128 b4e3a8a84ade44ac3dd9102b792cdb4311a95937
v4.5.112 bfe3d94bad6db92fc2927c2e3c081ae8303e209e
Suggested affected range: praisonai >= 4.5.112, <= 4.6.58.
The lower bound is conservative and based on sampled tags. Maintainers should confirm the exact introduction point before publishing a final range.
Root cause
The installed entrypoint routes registered Typer commands before falling back to the legacy dispatcher:
if first_cmd in _get_typer_commands():
_run_typer(argv)
else:
_run_legacy(argv)
cli/app.py registers commands.recipe as the recipe Typer command:
from .commands.recipe import app as recipe_app
...
app.add_typer(recipe_app, name="recipe", help="Recipe management")
The deprecated Typer recipe serve implementation accepts a remote host,
defaults CORS to *, and only enables authentication when --api-key is
explicitly provided:
host: str = typer.Option("127.0.0.1", "--host", "-h", ...)
api_key: str = typer.Option(None, "--api-key", ...)
cors: str = typer.Option("*", "--cors", ...)
admin: bool = typer.Option(False, "--admin", ...)
...
serve_config = {}
...
if api_key:
serve_config["api_key"] = api_key
serve_config["auth"] = "api-key"
if cors:
serve_config["cors_origins"] = cors
if admin:
serve_config["enable_admin"] = True
...
serve(host=host, port=port, reload=reload, config=serve_config, workers=workers)
There is no equivalent to the hardened non-localhost guard in the legacy feature handler:
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
The Recipe server only installs auth middleware when config["auth"] is set:
auth_type = config.get("auth")
if auth_type and auth_type != "none":
auth_middleware = create_auth_middleware(...)
if auth_middleware:
middleware.append(Middleware(auth_middleware))
On current v4.6.58, the…
- Record
GHSA-5qw8-f2g9-ff29- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N - Weakness
- CWE-287, CWE-306, CWE-862
- Updated
- 2026-11-02
OSVPYSEC-2026-3502
8.2
PraisonAI recipe serve Typer command bypasses the non-localhost authentication guard
PraisonAI recipe serve Typer command bypasses the non-localhost authentication guard
Summary
PraisonAI's installed console entrypoint is Typer-first. In current releases,
the recipe command is registered in the Typer app and
praisonai recipe serve dispatches to the deprecated Typer command in
src/praisonai/praisonai/cli/commands/recipe.py.
That Typer command can start the Recipe HTTP server on a non-localhost interface with no authentication:
praisonai recipe serve --host 0.0.0.0 --admin
It prints a deprecation warning, then launches the server with:
{
"host": "0.0.0.0",
"config": {
"cors_origins": "*",
"enable_admin": true
}
}
Because config.auth is absent, create_app() does not attach the API-key or
JWT middleware. Unauthenticated requests can then reach the recipe API and, when
enabled, /admin/reload.
This is an incomplete hardening / sibling-callsite issue. The legacy feature
handler in src/praisonai/praisonai/cli/features/recipe.py rejects the same
non-localhost/no-auth combination, and current create_auth_middleware() now
fails closed if API-key/JWT auth is selected without a secret. The installed
Typer command bypasses both expectations by never requiring or setting auth.
Affected product
- Repository:
MervinPraison/PraisonAI - Package:
praisonai - Component:
src/praisonai/praisonai/__main__.pysrc/praisonai/praisonai/cli/app.pysrc/praisonai/praisonai/cli/commands/recipe.pysrc/praisonai/praisonai/cli/features/recipe.pysrc/praisonai/praisonai/recipe/serve.py
Confirmed affected:
v4.6.58 1ad58ca02975ff1398efeda694ea2ab78f20cf3e
v4.6.57 e90d92231853161ad931f3498da57651a9f8b528
v4.6.56 d3c4a2afadfbf3a3e172e460e607ba4efad263a6
v4.6.34 e5928449f73f66cc8af1de61621aa974ab255133
v4.6.33 dfbb8d78ec7e8dc7118bc722ab1b2524bc98ddab
v4.6.10 4b1b17b963cbd0625e41394a30168c95b26429b2
v4.5.128 b4e3a8a84ade44ac3dd9102b792cdb4311a95937
v4.5.112 bfe3d94bad6db92fc2927c2e3c081ae8303e209e
Suggested affected range: praisonai >= 4.5.112, <= 4.6.58.
The lower bound is conservative and based on sampled tags. Maintainers should confirm the exact introduction point before publishing a final range.
Root cause
The installed entrypoint routes registered Typer commands before falling back to the legacy dispatcher:
if first_cmd in _get_typer_commands():
_run_typer(argv)
else:
_run_legacy(argv)
cli/app.py registers commands.recipe as the recipe Typer command:
from .commands.recipe import app as recipe_app
...
app.add_typer(recipe_app, name="recipe", help="Recipe management")
The deprecated Typer recipe serve implementation accepts a remote host,
defaults CORS to *, and only enables authentication when --api-key is
explicitly provided:
host: str = typer.Option("127.0.0.1", "--host", "-h", ...)
api_key: str = typer.Option(None, "--api-key", ...)
cors: str = typer.Option("*", "--cors", ...)
admin: bool = typer.Option(False, "--admin", ...)
...
serve_config = {}
...
if api_key:
serve_config["api_key"] = api_key
serve_config["auth"] = "api-key"
if cors:
serve_config["cors_origins"] = cors
if admin:
serve_config["enable_admin"] = True
...
serve(host=host, port=port, reload=reload, config=serve_config, workers=workers)
There is no equivalent to the hardened non-localhost guard in the legacy feature handler:
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
The Recipe server only installs auth middleware when config["auth"] is set:
auth_type = config.get("auth")
if auth_type and auth_type != "none":
auth_middleware = create_auth_middleware(...)
if auth_middleware:
middleware.append(Middleware(auth_middleware))
On current v4.6.58, the…
- Record
PYSEC-2026-3502- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
praisonaiPyPI |
4.5.112 to 4.6.58 | 4.6.59 |
praisonaiPyPI |
4.5.112 up to 4.6.59, plus listed versions 4.5.1134.5.1144.5.1154.5.1174.5.118 Show 45 moreShow less4.5.1194.5.1204.5.1214.5.1224.5.1234.5.1244.5.1254.5.1264.5.1274.5.1284.5.1294.5.1304.5.1314.5.1324.5.1334.5.1344.5.1354.5.1364.5.1374.5.1394.5.1404.5.1434.5.1444.5.1454.5.1494.6.104.6.114.6.124.6.134.6.144.6.154.6.164.6.184.6.194.6.204.6.214.6.224.6.234.6.244.6.254.6.264.6.274.6.284.6.294.6.30 |
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-56836 is a high vulnerability (CVSS 8.2) 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.33%, the 26th percentile. Fixed in praisonai 4.6.59.
References
Left out here: 28 versions and the rest of 3 source descriptions. The JSON record has them.