Dev.to Security 🔐 Cybersecurity 👁 0 📖 4 min read

AI Execution Governance, Part 10: Can Revocation Stop a Call That Is Already Running?

A tool call has passed the gate and is running. Now the role is revoked. Does it stop, or does it finish? Ours finishes. Revocation governs the next call, not this one. That is not the intent of the design; it is what

A tool call has passed the gate and is running. Now the role is revoked.

Does it stop, or does it finish?

Ours finishes. Revocation governs the next call, not this one.

That is not the intent of the design; it is what the current implementation does. Three things follow: what each of the three "undo" acts actually stops, when the gate takes effect, and what would have to be added for a call to be stoppable. If the first sentence is enough, the rest can be skipped.

  1. Three "undo" acts are not one
    Revocation acts on a permission, before a call starts. Evidence it leaves: the next call is refused.
    Cancellation acts on the call itself, while it runs. Evidence it leaves today: none, because there is no cancellation channel.
    Revocation of effects acts after execution. Evidence it leaves: a compensation record that can be checked later.
    Collapse them into one word and the usual false sentence appears: "it is revoked, so it stopped." What stopped may have been only the next call.

  2. When the gate takes effect
    The write path runs four checks at the execution entry:

whether the tool is enabled and the role is allowed (irreversible actions are blocked outright);
whether the arguments stay inside the declared writable field domain and destination allowlist;
whether the destination bound at confirmation time is still the destination now;
whether the approval requirement still holds (a single confirmation is not a second person's approval).
The third applies only to writes that carry a confirmation artifact. An automatic write with no artifact is not subject to it.

All four run before the tool's own code starts. The role is read from the database on every call, so a revocation takes effect on the next call immediately. For the call that has already entered, there is no second look.

It also means revocation during the confirmation or approval wait is effective: the four checks run again before the tool actually executes. Revocation stops being able to stop the call only once execute has begun.

await gate.assertToolAllowed(toolName, userId);
await gate.assertWithinDeclaredScope(toolName, args, userId);
// destination binding, approval requirement...
const result = await tool.execute(args, userId); // from here, no path back to the gate
In the same system, the model HTTP path does have a ceiling: the proxy aborts the request with AbortController when it times out. The tool execution path has nothing equivalent. The two paths do not share a boundary, and that is not a typo.

  1. Three gaps The tool signature is execute(args, userId). No signal, no abort. The executor has no AbortController, no Promise.race, no timeout. The abort on the realtime channel stops the stream, not a tool call already sent. Together: there is no kill switch today.

One boundary worth stating: the module does contain other timeouts — one around evaluation batches, one around probing an external tool's status — but neither sits on the tool execution path. They cannot stand in for the missing one.

  1. What it would take Two options, or both.

A cancellation contract. The tool signature takes a signal; a long call that is aborted returns "aborted", and the side-effect ledger records "aborted" rather than "executed". Passing the signal is the easy part. The hard part is that after an abort the ledger has to say what the target actually did.

A bounded window. Local tools take milliseconds; calls that leave the system get a ceiling, and anything past it is unknown, not success. This one does not require changing every tool signature, but it does require every outbound call to share the same ceiling.

Either option can be written as an acceptance check that can fail: revoke a role during a long call and the call is aborted, with the ledger recording an abort; exceed the window and the conclusion is unknown, never success.

Three questions for your own system:

Does your tool signature carry a cancellation signal?
Does the executor put a ceiling on a single call?
When a role is revoked, does the system ever read a state called "in flight"?

  1. Three limits Cancellation contract, bounded window and an aborted state are all absent today. The verification level here is design. This comes from reading the code, not from an end-to-end test. The cost of changing the tool interface everywhere is not estimated. There are 61 tools; this is not a one-parameter change. Closing Revocation is an act on a permission. Cancellation is an act on an execution. Treating the first as the second is how you discover, at the moment you most need to stop, that nothing stops.

What we can honestly deliver is the ledger: a call that finishes is still recorded, and can be revoked or compensated afterwards. That is weaker than stopping it, but it is not the sentence "already revoked".

The implementation described here comes from the open-source project KeelBase:
https://github.com/rain6fish/KeelBase

Drafted with an AI assistant. The system, the positions and the mistakes are mine.

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.