# PraisonAI recipe workflow policy can be bypassed by declaring and YAML-approving dangerous tools outside TEMPLATE.yaml

PraisonAI recipe policy only checks TEMPLATE.yaml requires.tools, so a recipe can declare execute_command in workflow.yaml and self-approve it via top-level approve:, bypassing allow_dangerous_tools.

- Payout: Research
- Severity: high
- Program: PraisonAI
- Found by: rexpository
- Disclosed: 2026-06-18
- CVE: CVE-2026-57142
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-7qw2-w5rc-37x2
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-7qw2-w5rc-37x2
- Tags: area:ai domain:ai impact:privesc impact:rce kind:research platform:ghsa sev:high tech:python technique:source-review vuln:access-control vuln:command-injection vuln:misconfiguration vuln:rce

**Target:** PraisonAI recipe runner / YAMLWorkflowParser workflow approval path
**Root cause:** Recipe dangerous-tool policy (_check_tool_policy) only inspects TEMPLATE.yaml requires.tools, while the steps workflow path loads workflow.yaml agents.*.tools and top-level approve: into the approval registry, so a recipe can supply and self-approve a default-denied critical tool.
**Steps:**
1. Create control recipe with `TEMPLATE.yaml requires.tools: [execute_command]`; `recipe.run()` returns `policy_denied` with "Tool 'execute_command' is denied by default. Use allow_dangerous_tools=True to override."
2. Create bypass recipe with no dangerous tools in `TEMPLATE.yaml`, but `workflow.yaml` declaring `execute_command` under an agent and top-level `approve: [execute_command]`.
3. Run `recipe.run(..., dry_run=True)`; policy check passes (bypass_policy null) and status reaches `dry_run`.
4. YAMLWorkflowParser resolves agents.*.tools and approve:, Workflow.start() calls set_yaml_approved_tools(approve_tools), registry treats execute_command as approved.
5. Workflow runs `execute_command` (PoV uses harmless `printf poc`) with PraisonAI process privileges.
**How found:** Noticed the recipe policy reads required tools only from TEMPLATE.yaml requires.tools, while the steps execution path separately parses workflow.yaml via YAMLWorkflowParser which resolves agents.*.tools and preserves top-level approve:; hypothesized the two paths disagree and tested a control vs bypass recipe.
**Exploitation:** An operator running an untrusted recipe, or a user who can choose recipe names/URIs on an authenticated HTTP recipe-runner deployment, supplies a recipe whose workflow.yaml declares execute_command and approve: [execute_command]. The recipe passes the dangerous-tool policy without allow_dangerous_tools=True and the workflow self-approves the critical shell tool, executing commands as the PraisonAI process once the agent reaches the tool call.
**Escalation:** Local CLI recipe execution escalates to authenticated remote recipe-execution (RCE) if the HTTP sidecar is exposed to users who control recipe names/URIs; default localhost/no-auth limits default severity.
**Insight:** When a policy gate reads one config source but execution reads another (TEMPLATE.yaml vs workflow.yaml), enumerate every file the execution path parses for tool/privilege declarations and check whether any of them also carries an approval/allowlist field the recipe itself controls.

