Skip to content

Refuse a consumed or earlier-session approval presented again - #294

Open
astrogilda wants to merge 4 commits into
GenAI-Security-Project:integrationfrom
astrogilda-forks:spec/approval-lifetime
Open

astrogilda wants to merge 4 commits into
GenAI-Security-Project:integrationfrom
astrogilda-forks:spec/approval-lifetime

Conversation

@astrogilda

@astrogilda astrogilda commented Oct 17, 2026 •

Copy link
Copy Markdown

What changed

@bar-capsule, @afogel, @rocklambros, this PR adds section 9.3 to the specification with the sentence proposed on #53:

A Guardian MUST refuse a consumed one-time approval, or one bound to an earlier session, presented again in a fresh signed request.

Section 9.3 defines one-time, consumed and session-bound grants and registers REPLAY_CONSUMED in 17.1 as -32009, leaving -32008 to Discussion #257. ACS v0.1 has no request field that names a grant, so the testable half is reuse. After an ASK is approved, the Guardian decides the repeat request, and one more repeat gets no approval. @avp9-nexus, -32009 is the 17.1 code for the two REPLAY_CONSUMED vectors on your negative-vectors-v0.2 branch.

9.3 also covers the lost-response case from #53. An approved action can run while its response never reaches the agent, for example when the target's reply is lost, so the action may have taken effect although the agent never saw a result and so cannot report one. A retry is then a new request. A fresh approval for it does not settle whether the first try took effect. The approver SHOULD NOT grant a retry of a non-idempotent action until the deployment has determined, outside ACS, that the first try did not commit. v0.1 has no field for that.

Which issue does this implement

Part of #33; refs #53.

I tested this

At 3c08c3f, the head of this branch, pytest gives 923 passed and the strict mkdocs build passes.

Edited 2026-10-22: the reuse sentence and the tested commit now match 4a6b5e0 (the approval covers the repeat request).

Edited 2026-10-24: added the 3c08c3f lost-response paragraph and its test run.

Section 10.3 defines a replay on the request: a duplicate request_id or
nonce within the session. A one-time approval already consumed, or a
grant from an earlier session, presented again in a fresh signed request
is neither, so no section refused it and 17.1 had no code for it.

Section 9.3 defines one-time, consumed and session-bound grants and
requires a Guardian to refuse such an approval with REPLAY_CONSUMED,
registered as -32009 because -32008 is proposed for a retryable overload
code. Section 10.3 and the ACS-Core list point at the new section.

Signed-off-by: Sankalp Gilda <23521054+astrogilda@users.noreply.github.com>
The section no longer touches the ACS-Core list, which is the Spec
workstream's call for a later release. It says that v0.1 has no request
field naming a grant, so the reuse rule is the half a wire test can
observe, and that a second request presenting a one-time approval is
refused even before the first decision returns.

Signed-off-by: Sankalp Gilda <23521054+astrogilda@users.noreply.github.com>
@President

Copy link
Copy Markdown

@astrogilda, +1.

One wording point:

After an ASK, the agent sends the approved action again with a NEW request_id (§10.3 refuses the old one).
But:

It authorizes one request: the request the ASK was raised for, identified by that request's request_id

could be read as if the repeat must reuse the same request_id.

Maybe a bit clearer:

It authorizes one request: a new request that repeats the action the original ASK was raised for and refers to that original ASK's request_id.

The PR notes that v0.1 has no request field for this reference.
I proposed one in #175 (ask_resolution.ask_request_id):
the two fit together - this PR says when an approval can't be used again, #175 how the approval reaches the Guardian.

The request an ASK was raised for already received the ASK, and 10.3
refuses its request_id a second time, so the approval can only reach
the Guardian on a new request that repeats the action. Section 9.3 now
says the grant authorizes that new request, which refers to the
original request's request_id, and the wire test approves an ASK, lets
the approved repeat be decided, and checks that a further repeat does
not inherit the approval.

Signed-off-by: Sankalp Gilda <23521054+astrogilda@users.noreply.github.com>
@astrogilda

Copy link
Copy Markdown
Author

@President thanks, good catch: an ASK has no request_id, and 10.3 refuses the asked request's id again, so approval needs a new request. 4a6b5e0 takes your wording but says the repeat "refers to the original request's request_id", and updates 9.3's presenting paragraph and v0.1 wire test to match.

Agreed on #175: ask_resolution.ask_request_id is the field 9.3 says v0.1 lacks.

…esponse

An approved action can run while its result is lost, and a retry under
a new request_id then needs a fresh approval. That approval covers the
retry but cannot say whether the first attempt committed. For an action
that is not idempotent, the approver should wait for an out-of-band
determination that it did not take effect, which v0.1 has no field for.

Signed-off-by: Sankalp Gilda <23521054+astrogilda@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

2 participants