Separates model tool proposals from authorization: every call requires policy approval, high-impact mutations require an action-bound approval, and idempotency prevents duplicate execution without granting permission.
Package status: reference context ready for human review. The contract and test scenarios are complete, but no claim is made that an adopting implementation has passed them.
Decision
The model may propose a tool name and arguments; a policy engine decides whether the call runs. Read tools that cannot change durable state may execute after ACL checks. Every mutation requires session authorization. High-impact, irreversible, financial, administrative, or externally visible mutations additionally require an unexpired approval artifact bound to the exact actor, tool, target, and normalized arguments. An idempotency key is replay protection only: it can repeat an already authorized operation safely, but it never grants authority or replaces approval. The acting user, tenant, and roles come from the authenticated request context, never from fields the model generated.
Scope
- Agent tool dispatch on the backend: proposal, authorization, confirmation, dry-run, idempotency, and audit.
- Side-effecting tools such as tickets, refunds, deploys, or record updates.
- Binding tool ACL to the human principal who owns the agent session.
Outside this block
- Prompt-injection content filters for retrieved documents.
- Frontend streaming cancellation of tokens already displayed.
Contract
- Every tool invocation record stores
proposed_by: modelandauthorized_byas a policy decision on session identity. - Tools marked
mutation: trueexecute only after session authorization. When policy classifies the action as high impact, an action-boundapproval_idis also required. - Dry-run is mandatory for mutating tools when
require_dry_runis true; the dry-run result is what the human confirms. - Arguments that name a different user or tenant than the session are rejected as
identity_spoof. - Tool ACL is evaluated on the session principal against resource identifiers after argument schema validation.
- An idempotency key is accepted only with the same actor, tool, target, and request fingerprint as the authorized original call. It replays the stored result and never authorizes a first call by itself.
Implementation
- Keep mutation flags, confirmation policy, and dry-run support in a tool catalog, not in prompt text.
- Issue short-lived approval artifacts that hash the dry-run snapshot and bind actor, tool, target, policy version, and normalized arguments so an argument swap cannot reuse approval.
Failure handling
- Policy deny returns
tool_forbiddenwithout calling the provider. - Expired approval artifacts fail closed. After an uncertain timeout, reconcile the original operation before retrying with the same idempotency key and unchanged request fingerprint.
Verification
- Attempt a mutate with a model-supplied user id and expect
identity_spoof. - Confirm a dry-run, change arguments, and expect confirmation mismatch; replay the same key and assert one side effect.
The executable-looking examples in this package are fixtures and acceptance contracts. Run
python tools/validate.py from the collection root to check package structure and metadata; then
implement and execute the scenarios in the target repository.
Adoption assumptions
- Names and numeric values in
example.yamlare an adoption profile, not universal defaults. - The adopting team must map actors, data classes, error vocabulary, and ownership to its system.
References
- OWASP AI Agent Security Cheat Sheet separates authorization, human approval, and replay protection for high-impact actions.