AI003 · STOA-LLM08-UNOBSERVED-APPROVAL
High-impact capability call site with no approval construct observed.
- OWASP: LLM08 Excessive Agency (v1.1); LLM06 (2025).
- Severity: info (review) · Gates: never.
- Kind: capability correlation (fires only inside agent-candidate files).
- Cadence: one finding per agent candidate.
Detection
Fires when all hold in an agent candidate (confidence ≥ medium):
1. A tool binding is observed (@tool, tools=[...], StructuredTool.from_function, server.tool(...), an AI-SDK tool() object). 2. A high-impact capability call site is present (payment access, DB write, email/message send, shell/code exec, filesystem write, cloud resource, source-control write). 3. No approval construct is observed anywhere in the file.
Approval constructs that suppress the finding: LangGraph interrupt(...) / interrupt_before / Command(resume=...); requires_approval=True, human_in_the_loop, needsApproval: true, HumanApprovalCallbackHandler; or an approve/confirm/authorize/consent/review guard.
Vulnerable → remediated
# FLAGGED — refund tool bound to an agent, no approval construct observed
@tool
def issue_refund(order_id, amount):
stripe.Refund.create(payment_intent=lookup(order_id), amount=int(amount * 100))
# NOT FLAGGED — a human-in-the-loop interrupt dominates the payment call
@tool
def issue_refund(order_id, amount):
if not interrupt({"action": "refund", "order": order_id}).get("approved"):
return "declined"
stripe.Refund.create(payment_intent=lookup(order_id), amount=int(amount * 100))
Finding message
Suppress: # stoa: ignore[AI003] reason