# Tool approval after execution

Approval hooks or policy checks that run after the tool call already executed or wrote

_Area: AI and LLM app security. Seen in 3 disclosed reports; latest 2026-09-04. Updated 2026-11-08._

## How it works

An agent framework promises that a tool call is gated by an approval decision. The gate is placed in the wrong spot: either the tool declares itself auto-approved, or the approval callback fires after the tool has already run. The assumption that breaks is "approval precedes side effect." When the check is a per-tool override or a post-hoc callback, the user's policy is never consulted before the write, and a denial is reported after the damage.

## Where it shows up

- A tool trait with a default of `Required` for code-executing tools, overridden per tool to `Auto` [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-wrj3-vj8c-784f.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-g29h-pfmp-qp9r.md).
- A gate that ANDs `requirement != Auto` with `!auto_approve`, so one `Auto` short-circuits the global policy [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-wrj3-vj8c-784f.md).
- An `onToolCall`/approval callback documented as a gate but invoked after `generateText()` returns tool results [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-h2w2-v7j6-xqm4.md).
- Interactive-session tools (stdin to a live shell) that skip the prompt their sibling `exec` tool enforces [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-g29h-pfmp-qp9r.md).
- Sibling tools patched for missing approval while others with the same capability are not [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-wrj3-vj8c-784f.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-g29h-pfmp-qp9r.md).

## How to review

For every tool that executes code, writes files, or sends input to a process, find its declared approval requirement and compare it to its capabilities. The invariant: any tool whose capability is `ExecutesCode` (or equivalent) must return `Required`, and the approval decision must be evaluated before the tool body runs. For SDK wrappers, check whether the approval callback is wired to the SDK's pre-execution boundary (`needsApproval`) or merely runs after results materialize [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-h2w2-v7j6-xqm4.md). Grep the whole tool registry for `Auto` overrides and diff each against the trait default [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-wrj3-vj8c-784f.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-g29h-pfmp-qp9r.md).

## How finders spotted it

- Compared a suspect tool against an already-patched sibling, noticed the fix never reached it, then traced `approval_requirement()` into the engine gate to confirm `Auto` makes approval false [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-wrj3-vj8c-784f.md).
- Read `agent-loop.ts`, saw the approval hook placed after `generateText()` and tool-result materialization, contradicting the SDK's pre-execution model; confirmed ordering with a deterministic mock [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-h2w2-v7j6-xqm4.md).
- Diffed `exec_shell` (correctly gated) against `exec_shell_interact`, spotted the `Auto` override against the trait default, confirmed via a pty-driven TUI that no dialog appears [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-g29h-pfmp-qp9r.md).

## Variants seen

- Per-tool `Auto` override defeating a global `--approval-policy` [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-wrj3-vj8c-784f.md).
- Post-execution callback in an SDK wrapper reporting `tool_rejected` after the side effect [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-h2w2-v7j6-xqm4.md).
- Auto-approved stdin writes to an already-approved interactive shell [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-g29h-pfmp-qp9r.md).

## Impact and severity

Unsandboxed host code execution from model-supplied input [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-wrj3-vj8c-784f.md); denied tools still executing [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-h2w2-v7j6-xqm4.md); commands at the privilege of the approved process, scaling with what was launched (`mysql -u root`, `ssh host`, `sudo -i`) [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-g29h-pfmp-qp9r.md). Impact rises when combined with prompt injection and with staging tools like `rlm_open` that widen the injection surface before execution [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-wrj3-vj8c-784f.md).

## Seen in real software
Open-source packages and projects, and products, where this pattern was found. If the target runs one, compare the version it runs with the fix.
- **deepseek-tui (rust)** >= 0.8.33, <= 0.8.41, no fix yet: CodeWhale: rlm_eval auto-approves arbitrary Python execution, bypassing the user's approval policy (RCE) (CVE-2026-75858). Report: https://bugbountylibrary.com/r/ghsa%3AGHSA-wrj3-vj8c-784f.md. Fix: https://github.com/Hmbown/CodeWhale/commit/57f3c89471e27ac4032d9791f6885e5d4408c381
- **deepseek-tui (rust)** >= 0.3.10, <= 0.8.41, no fix yet: CodeWhale: exec_shell_interact sends LLM-controlled input to a running shell without an approval prompt (privilege escal (CVE-2026-75857). Report: https://bugbountylibrary.com/r/ghsa%3AGHSA-g29h-pfmp-qp9r.md. Fix: https://github.com/Hmbown/CodeWhale/commit/57f3c89471e27ac4032d9791f6885e5d4408c381
- **praisonai (npm)** >= 1.4.0, <= 1.7.1, fixed in 1.7.2: npm PraisonAI AgentLoop onToolCall approval runs after tool execution (CVE-2026-57137). Report: https://bugbountylibrary.com/r/ghsa%3AGHSA-h2w2-v7j6-xqm4.md

## Evidence
- E1: https://bugbountylibrary.com/r/ghsa%3AGHSA-wrj3-vj8c-784f.md
- E2: https://bugbountylibrary.com/r/ghsa%3AGHSA-h2w2-v7j6-xqm4.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-g29h-pfmp-qp9r.md
