01 / The operating case
What changes in a real workflow?
A transfer tool is permitted, but a $900 transfer to an approved vendor is different from $90,000 to a new counterparty.
- 01Authority origin
- 02Task and grant
- 03Current decision
- 04Observed outcome
02 / Decision contract
What the executor must check
Validate normalized amount, currency, beneficiary, account and task identifier after the agent has produced arguments and immediately before execution.
Architecture review / negative test
Make the boundary testable.
Normalize arguments before policy evaluation so equivalent representations of the same amount, account or resource receive the same result. Be explicit about currency conversion, alias resolution and fields omitted by a client. If the executor can alter values after the check, bind it to the normalized request or recheck immediately before commit.
03 / Failure and evidence
What goes wrong, and what can be proven?
A check on the tool name alone allows a permitted interface to carry impermissible parameters.
Retain a canonical hash of evaluated arguments and reject any execution with changed values.
04 / Canonical scope
Why this reference stands alone
Action-level authorization owns the verb; this page owns the value-sensitive decision within that verb.
Implementation review
Normalize arguments before the check and freeze them through execution.
Parameter policy fails when the decision service sees a friendly display string but the executor acts on a different canonical target. Resolve aliases, units and account identifiers before approval and before evaluation. Bind the decision to the canonical request, then have the executor reject substitutions. The permitted verb “transfer” has no safe meaning without payee, account, amount, currency and any aggregate limit.
proposal: transfer("Vendor A", 8.4, "thousand USD")
canonical: account=VENDOR-001, amount_minor=840000, currency=USD
request_digest: H(canonical + task + grant)
approval: H
executor receives account=VENDOR-002 → DENYRun the denial test
Use an alias that resolves to a new account after approval, or switch currency units while preserving the displayed number. Re-resolve and compare at execution; reject if the digest or policy-relevant values change.
Evidence to examine
Keep the submitted raw values, trusted canonical values, resolver version, decision digest, approval and executor comparison result. Avoid storing full account data where a stable reference is sufficient.
Primary source: OWASP Agent Control Standard ↗
Related: Approval expiry and binding.
Architecture field test
Normalize, decide, compare
Which request values determine the effect?
- 01Resolve aliases and units
- 02Build canonical request
- 03Evaluate bounded values
- 04Compare identical payload at executor
Work the boundary
A user sees “Vendor A, 8.4 thousand USD.” The resolver turns that display into account V-001 and 840000 minor currency units before authorization. An executor resolving Vendor A to V-002 must reject rather than reuse the old approval.
| Required facts | Canonical amount and currency, stable beneficiary or resource ID, task, policy and a digest over relevant arguments. |
|---|---|
| Allow only when | The executed arguments exactly match the evaluated request and remain inside the grant. |
| Deny when | A permitted transfer tool receives a different payee or amount after the decision. |
Break the assumption
Race an alias update against a delayed queue message; vary currency, case and whitespace while preserving display similarity. The policy must compare canonical values, not raw text alone.
Design tradeoff
Canonicalization can itself be stale or ambiguous. Preserve resolver version and reject unresolved targets; do not rely on a display string as the enforcement key.
For normalize, decide, compare, consult OWASP AI Agent Security Cheat Sheet. This worked decision and negative test are ProofGrid analysis.
Continue with Action-level authorization.
Primary references