Every CVE Search/ Get API key

CVE-2026-56838

PraisonAI recipe.run_stream skips dangerous-tool policy enforcement

7.8 HighFix available

PraisonAI is a multi-agent teams system. From version 4.5.87 to before version 4.6.59, PraisonAI recipe execution blocks default-denied dangerous tools unless the caller explicitly passes allow_dangerous_tools=True. The normal recipe.run() path enforces this with _check_tool_policy(). The streaming path, recipe.run_stream(), loads the same recipe, checks dependencies, and then calls _execute_recipe() without running the dangerous-tool policy check. As a result, a recipe that honestly declares execute_command in TEMPLATE.yaml requires.tools is denied by recipe.run(), but reaches the execution engine through recipe.run_stream() with allow_dangerous_tools=False. This issue has been patched in version 4.6.59.

Attack profile

How easy it is to exploit

Attack vector
Local
Complexity
Low
Privileges needed
None
User interaction
Required

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
High

Exploit likelihood

0.15%Down 0.1 points since Oct 24, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.8

PraisonAI recipe.run_stream skips dangerous-tool policy enforcement

PraisonAI is a multi-agent teams system. From version 4.5.87 to before version 4.6.59, PraisonAI recipe execution blocks default-denied dangerous tools unless the caller explicitly passes allow_dangerous_tools=True. The normal recipe.run() path enforces this with _check_tool_policy(). The streaming path, recipe.run_stream(), loads the same recipe, checks dependencies, and then calls _execute_recipe() without running the dangerous-tool policy check. As a result, a recipe that honestly declares execute_command in TEMPLATE.yaml requires.tools is denied by recipe.run(), but reaches the execution engine through recipe.run_stream() with allow_dangerous_tools=False. This issue has been patched in version 4.6.59.

Record
CVE-2026-56838
CVSS 3.1
7.8 HighCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Weakness
CWE-78, CWE-693, CWE-863
Updated
2026-11-02
EUVDEUVD-2026-108879 7.8

PraisonAI is a multi-agent teams system. From version 4.5.87 to before version 4.6.59, PraisonAI recipe execution blocks default-denied dangerous tools unless the caller explicitly passes allow_dangerous_tools=True. The normal recipe.run() path enforces this with _check_tool_policy(). The streaming path, recipe.run_stream(), loads the same recipe, checks dependencies, and then calls _execute_recipe() without running the dangerous-tool policy check. As a result, a recipe that honestly declares execute_command in TEMPLATE.yaml requires.tools is denied by recipe.run(), but reaches the execution engine through recipe.run_stream() with allow_dangerous_tools=False. This issue has been patched in version 4.6.59.

Record
EUVD-2026-108879
CVSS 3.1
7.8 HighCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-v847-hxxw-3pxg 7.8

PraisonAI recipe.run_stream skips dangerous-tool policy enforcement

PraisonAI recipe.run_stream() skips dangerous-tool policy enforcement

Summary

PraisonAI recipe execution blocks default-denied dangerous tools unless the caller explicitly passes allow_dangerous_tools=True. The normal recipe.run() path enforces this with _check_tool_policy(). The streaming path, recipe.run_stream(), loads the same recipe, checks dependencies, and then calls _execute_recipe() without running the dangerous-tool policy check.

As a result, a recipe that honestly declares execute_command in TEMPLATE.yaml requires.tools is denied by recipe.run(), but reaches the execution engine through recipe.run_stream() with allow_dangerous_tools=False.

The local PoV uses a harmless printf canary, explicitly unsets PRAISONAI_AUTO_APPROVE, and avoids network access.

Affected Product

  • Repository: MervinPraison/PraisonAI
  • Package: praisonai
  • Components:
    • src/praisonai/praisonai/recipe/core.py
    • src/praisonai/praisonai/recipe/serve.py
    • src/praisonai/praisonai/cli/features/recipe.py
    • src/praisonai-agents/praisonaiagents/workflows/yaml_parser.py
    • src/praisonai-agents/praisonaiagents/workflows/workflows.py

Validated affected:

  • current main 2f9677abb2ea68eab864ee8b6a828fd0141612e1 (v4.6.57-4-g2f9677ab)
  • v4.6.57
  • v4.6.56
  • v4.6.10
  • v4.6.9
  • v4.5.128
  • v4.5.120
  • v4.5.96
  • v4.5.87

Suggested affected range: >= 4.5.87, <= 4.6.57.

PyPI lists PraisonAI 4.6.57 as the latest release on 2026-06-13.

Earlier tested tags through v4.5.85 failed in this source checkout before the tested workflow path due an unrelated praisonaiagents.output.models import error. They are not claimed fixed or unaffected.

Root Cause

recipe.run() enforces the dangerous-tool gate:

if not options.get("allow_dangerous_tools", False):
    policy_error = _check_tool_policy(recipe_config)
    if policy_error:
        return RecipeResult(..., status=RecipeStatus.POLICY_DENIED, ...)

recipe.run_stream() has a sibling execution path. It loads the recipe and checks dependencies, but then goes directly to execution:

recipe_config = _load_recipe(name, offline=options.get("offline", False))
...
output = _execute_recipe(recipe_config, merged_config, session_id, options)

There is no equivalent _check_tool_policy() call in run_stream() before execution or before the dry-run shortcut.

The CLI exposes this path via praisonai recipe run <recipe> --stream, and the recipe HTTP server exposes it as POST /v1/recipes/stream.

Why This Is Not Intended Behavior

The normal recipe path clearly treats declared dangerous tools as denied by default. A control recipe with TEMPLATE.yaml requires.tools: [execute_command] returns:

Tool 'execute_command' is denied by default. Use allow_dangerous_tools=True to override.

That operator-facing override should not depend on whether the caller requests streaming output. PraisonAI's own docs describe approval as requiring a human or configured channel before risky tools run, describe security environment variables as opt-in access for dangerous operations with secure defaults, and describe policy controls as blocking dangerous operations.

This is distinct from the prior report PRAI-CAND-011:

  • PRAI-CAND-011 covers workflow tool declarations that are omitted from TEMPLATE.yaml requires.tools.
  • This report covers a sibling entrypoint that skips the policy check even when TEMPLATE.yaml correctly declares the dangerous tool.

It is also distinct from the published Recipe-server authentication fail-open advisory. That advisory covers missing authentication secrets. This report assumes the attacker has whatever access is already needed to invoke recipe streaming and focuses on the missing dangerous-tool policy guard.

Local PoV

Run:

python3 poc/pov_prai_cand_012_stream_policy_bypass.py

Expected output includes:

{
  "ok": true,
  "policy_error": "Tool…
Record
GHSA-v847-hxxw-3pxg
CVSS 3.1
7.8 HighCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Weakness
CWE-78, CWE-693, CWE-863
Updated
2026-11-02
NVD 7.8

PraisonAI is a multi-agent teams system. From version 4.5.87 to before version 4.6.59, PraisonAI recipe execution blocks default-denied dangerous tools unless the caller explicitly passes allow_dangerous_tools=True. The normal recipe.run() path enforces this with _check_tool_policy(). The streaming path, recipe.run_stream(), loads the same recipe, checks dependencies, and then calls _execute_recipe() without running the dangerous-tool policy check. As a result, a recipe that honestly declares execute_command in TEMPLATE.yaml requires.tools is denied by recipe.run(), but reaches the execution engine through recipe.run_stream() with allow_dangerous_tools=False. This issue has been patched in version 4.6.59.

Record
CVE-2026-56838
CVSS 3.1
7.8 HighCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Weakness
CWE-78, CWE-693, CWE-863
Updated
2026-11-02
OSV 7.8

PraisonAI recipe.run_stream skips dangerous-tool policy enforcement

PraisonAI is a multi-agent teams system. From version 4.5.87 to before version 4.6.59, PraisonAI recipe execution blocks default-denied dangerous tools unless the caller explicitly passes allow_dangerous_tools=True. The normal recipe.run() path enforces this with _check_tool_policy(). The streaming path, recipe.run_stream(), loads the same recipe, checks dependencies, and then calls _execute_recipe() without running the dangerous-tool policy check. As a result, a recipe that honestly declares execute_command in TEMPLATE.yaml requires.tools is denied by recipe.run(), but reaches the execution engine through recipe.run_stream() with allow_dangerous_tools=False. This issue has been patched in version 4.6.59.

Record
CVE-2026-56838
CVSS 3.1
7.8 HighCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Weakness
CWE-693, CWE-78, CWE-863
Updated
2026-11-02
OSVGHSA-v847-hxxw-3pxg 7.8

PraisonAI recipe.run_stream skips dangerous-tool policy enforcement

PraisonAI recipe.run_stream() skips dangerous-tool policy enforcement

Summary

PraisonAI recipe execution blocks default-denied dangerous tools unless the caller explicitly passes allow_dangerous_tools=True. The normal recipe.run() path enforces this with _check_tool_policy(). The streaming path, recipe.run_stream(), loads the same recipe, checks dependencies, and then calls _execute_recipe() without running the dangerous-tool policy check.

As a result, a recipe that honestly declares execute_command in TEMPLATE.yaml requires.tools is denied by recipe.run(), but reaches the execution engine through recipe.run_stream() with allow_dangerous_tools=False.

The local PoV uses a harmless printf canary, explicitly unsets PRAISONAI_AUTO_APPROVE, and avoids network access.

Affected Product

  • Repository: MervinPraison/PraisonAI
  • Package: praisonai
  • Components:
    • src/praisonai/praisonai/recipe/core.py
    • src/praisonai/praisonai/recipe/serve.py
    • src/praisonai/praisonai/cli/features/recipe.py
    • src/praisonai-agents/praisonaiagents/workflows/yaml_parser.py
    • src/praisonai-agents/praisonaiagents/workflows/workflows.py

Validated affected:

  • current main 2f9677abb2ea68eab864ee8b6a828fd0141612e1 (v4.6.57-4-g2f9677ab)
  • v4.6.57
  • v4.6.56
  • v4.6.10
  • v4.6.9
  • v4.5.128
  • v4.5.120
  • v4.5.96
  • v4.5.87

Suggested affected range: >= 4.5.87, <= 4.6.57.

PyPI lists PraisonAI 4.6.57 as the latest release on 2026-06-13.

Earlier tested tags through v4.5.85 failed in this source checkout before the tested workflow path due an unrelated praisonaiagents.output.models import error. They are not claimed fixed or unaffected.

Root Cause

recipe.run() enforces the dangerous-tool gate:

if not options.get("allow_dangerous_tools", False):
    policy_error = _check_tool_policy(recipe_config)
    if policy_error:
        return RecipeResult(..., status=RecipeStatus.POLICY_DENIED, ...)

recipe.run_stream() has a sibling execution path. It loads the recipe and checks dependencies, but then goes directly to execution:

recipe_config = _load_recipe(name, offline=options.get("offline", False))
...
output = _execute_recipe(recipe_config, merged_config, session_id, options)

There is no equivalent _check_tool_policy() call in run_stream() before execution or before the dry-run shortcut.

The CLI exposes this path via praisonai recipe run <recipe> --stream, and the recipe HTTP server exposes it as POST /v1/recipes/stream.

Why This Is Not Intended Behavior

The normal recipe path clearly treats declared dangerous tools as denied by default. A control recipe with TEMPLATE.yaml requires.tools: [execute_command] returns:

Tool 'execute_command' is denied by default. Use allow_dangerous_tools=True to override.

That operator-facing override should not depend on whether the caller requests streaming output. PraisonAI's own docs describe approval as requiring a human or configured channel before risky tools run, describe security environment variables as opt-in access for dangerous operations with secure defaults, and describe policy controls as blocking dangerous operations.

This is distinct from the prior report PRAI-CAND-011:

  • PRAI-CAND-011 covers workflow tool declarations that are omitted from TEMPLATE.yaml requires.tools.
  • This report covers a sibling entrypoint that skips the policy check even when TEMPLATE.yaml correctly declares the dangerous tool.

It is also distinct from the published Recipe-server authentication fail-open advisory. That advisory covers missing authentication secrets. This report assumes the attacker has whatever access is already needed to invoke recipe streaming and focuses on the missing dangerous-tool policy guard.

Local PoV

Run:

python3 poc/pov_prai_cand_012_stream_policy_bypass.py

Expected output includes:

{
  "ok": true,
  "policy_error": "Tool…
Record
GHSA-v847-hxxw-3pxg
CVSS 3.1
7.8 HighCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Weakness
CWE-693, CWE-78, CWE-863
Updated
2026-11-02
OSVPYSEC-2026-3520 7.8

PraisonAI recipe.run_stream skips dangerous-tool policy enforcement

PraisonAI recipe.run_stream() skips dangerous-tool policy enforcement

Summary

PraisonAI recipe execution blocks default-denied dangerous tools unless the caller explicitly passes allow_dangerous_tools=True. The normal recipe.run() path enforces this with _check_tool_policy(). The streaming path, recipe.run_stream(), loads the same recipe, checks dependencies, and then calls _execute_recipe() without running the dangerous-tool policy check.

As a result, a recipe that honestly declares execute_command in TEMPLATE.yaml requires.tools is denied by recipe.run(), but reaches the execution engine through recipe.run_stream() with allow_dangerous_tools=False.

The local PoV uses a harmless printf canary, explicitly unsets PRAISONAI_AUTO_APPROVE, and avoids network access.

Affected Product

  • Repository: MervinPraison/PraisonAI
  • Package: praisonai
  • Components:
    • src/praisonai/praisonai/recipe/core.py
    • src/praisonai/praisonai/recipe/serve.py
    • src/praisonai/praisonai/cli/features/recipe.py
    • src/praisonai-agents/praisonaiagents/workflows/yaml_parser.py
    • src/praisonai-agents/praisonaiagents/workflows/workflows.py

Validated affected:

  • current main 2f9677abb2ea68eab864ee8b6a828fd0141612e1 (v4.6.57-4-g2f9677ab)
  • v4.6.57
  • v4.6.56
  • v4.6.10
  • v4.6.9
  • v4.5.128
  • v4.5.120
  • v4.5.96
  • v4.5.87

Suggested affected range: >= 4.5.87, <= 4.6.57.

PyPI lists PraisonAI 4.6.57 as the latest release on 2026-06-13.

Earlier tested tags through v4.5.85 failed in this source checkout before the tested workflow path due an unrelated praisonaiagents.output.models import error. They are not claimed fixed or unaffected.

Root Cause

recipe.run() enforces the dangerous-tool gate:

if not options.get("allow_dangerous_tools", False):
    policy_error = _check_tool_policy(recipe_config)
    if policy_error:
        return RecipeResult(..., status=RecipeStatus.POLICY_DENIED, ...)

recipe.run_stream() has a sibling execution path. It loads the recipe and checks dependencies, but then goes directly to execution:

recipe_config = _load_recipe(name, offline=options.get("offline", False))
...
output = _execute_recipe(recipe_config, merged_config, session_id, options)

There is no equivalent _check_tool_policy() call in run_stream() before execution or before the dry-run shortcut.

The CLI exposes this path via praisonai recipe run <recipe> --stream, and the recipe HTTP server exposes it as POST /v1/recipes/stream.

Why This Is Not Intended Behavior

The normal recipe path clearly treats declared dangerous tools as denied by default. A control recipe with TEMPLATE.yaml requires.tools: [execute_command] returns:

Tool 'execute_command' is denied by default. Use allow_dangerous_tools=True to override.

That operator-facing override should not depend on whether the caller requests streaming output. PraisonAI's own docs describe approval as requiring a human or configured channel before risky tools run, describe security environment variables as opt-in access for dangerous operations with secure defaults, and describe policy controls as blocking dangerous operations.

This is distinct from the prior report PRAI-CAND-011:

  • PRAI-CAND-011 covers workflow tool declarations that are omitted from TEMPLATE.yaml requires.tools.
  • This report covers a sibling entrypoint that skips the policy check even when TEMPLATE.yaml correctly declares the dangerous tool.

It is also distinct from the published Recipe-server authentication fail-open advisory. That advisory covers missing authentication secrets. This report assumes the attacker has whatever access is already needed to invoke recipe streaming and focuses on the missing dangerous-tool policy guard.

Local PoV

Run:

python3 poc/pov_prai_cand_012_stream_policy_bypass.py

Expected output includes:

{
  "ok": true,
  "policy_error": "Tool…
Record
PYSEC-2026-3520
CVSS 3.1
7.8 HighCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
praisonai
PyPI
4.5.87 to 4.6.58
4.6.59
praisonai
PyPI
4.5.87 up to 4.6.59, plus listed versions
4.5.1004.5.1014.5.1024.5.1034.5.104
Show 45 moreShow less
4.5.1054.5.1064.5.1074.5.1084.5.1094.5.1104.5.1114.5.1124.5.1134.5.1144.5.1154.5.1174.5.1184.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.5.884.5.894.5.904.5.934.5.944.5.954.5.96
4.6.59

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-56838 is a high vulnerability (CVSS 7.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.15%, the 3rd percentile. Fixed in praisonai 4.6.59.

References

This page doesn't list everything

Left out here: 50 versions and the rest of 3 source descriptions. The JSON record has them.

MoveEnter Open