Investigation demonstrates a practical "loopjacking" risk in agent-to-agent (A2A) human-in-the-loop approval flows: an implementation can present operation A to an approver, accept a later same-Task update that replaces A with a materially different operation B, and then apply the approver's earlier decision to B. In a controlled LangGraph Agent Server composition, a maker created mock_wire_transfer(20, approved-vendor), the approver read that exact view, the maker then sent a message.command.update that replaced the pending tool-call (same IDs) with mock_wire_transfer(2000, attacker-sink), and when the approver submitted "approve" the system reconstructed the current thread state and executed the 2,000-unit transfer under the approver's authority. The experiment used an in-memory server, deterministic model, synthetic identities, a mock append-only ledger, and an auth policy that explicitly allowed the maker to update a pending thread but not to approve or execute; the ledger recorded the substituted 2,000-unit effect and controls confirmed the maker alone could not achieve that effect.
The root cause is conceptual: A2A Task coordination (Task ID, interrupted state) is separate from the approval record that must bind a human decision to a specific executable operation, and implementations that only check "task approved" can spend that approval on a different action. Earlier A2A text left TASK_STATE_AUTH_REQUIRED ambiguous; a merged clarification (PR #2081) makes clear it signals a need for authorization, not a reusable permission, and places responsibility on implementations or credential issuers to define and enforce approval scope. The vulnerability is implementation-level and preventable by explicitly recording the approved operation and re-checking it at execution time; the investigation verified traces across many LangGraph Agent Server releases and preserved request, decision, and ledger evidence.
Summary generated by AI from the linked article. hn.today is not affiliated with Hacker News or Y Combinator.