Abstract

Revocation looks simple in centralized systems.

An authorization is valid. Something changes. The authorization becomes invalid.

In distributed financial infrastructure, that transition is rarely atomic.

A capability may already exist in several services. A worker may be offline. A queue may contain delayed execution commands. A signer may have cached policy state. An external transaction may have been submitted but not confirmed. A revocation event may be committed in one region while another region continues operating from stale authority.

The financial question is therefore not merely:

Was the capability revoked? 

It is:

Which copies of that authority may still exist, which executions may already have started, which effects remain preventable, and which effects now require compensation? 

This article examines revocation as a distributed state transition under partial failure. We explore revocation epochs, bounded staleness, offline verification, execution leases, queue semantics, unknown outcomes, revocation races, cache invalidation, signer isolation, capability descendants, authority graph invalidation, and the difference between preventing future execution and compensating for authority that escaped before revocation converged.

The central idea is uncomfortable but necessary:

Revocation is not a boolean.

It is a race between authority propagation and authority invalidation.

Authority spreads faster than revocation

Consider a capability:

C: action = external_withdrawal amount = 500000 account = A expires_at = 14:10 

The capability is issued at 14:00.

It propagates through:

API -> orchestrator -> queue -> worker -> custody 

At 14:03, fraud detection decides the account must be frozen.

The system commits:

revoked(C) = true 

at 14:03:01.

But the capability may already exist in several places:

orchestrator memory queue payload worker local cache custody request retry buffer 

The revocation exists.

So does the authority.

For some period, both statements are true.

Revocation has several times

A useful revocation model distinguishes multiple timestamps.

For example:

decision_time commit_time publication_time observation_time enforcement_time 

Suppose:

14:03:00 risk decides to revoke 14:03:01 revocation committed 14:03:02 event published 14:03:05 worker observes event 14:03:07 custody cache invalidated 

What happened between 14:03:01 and 14:03:07?

The capability was revoked at the source.

It may still have been executable elsewhere.

That interval is revocation exposure.

Revocation exposure

Let:

T_commit = authoritative revocation commit time T_enforced = time all relevant execution points reject authority 

Then:

revocation_exposure_window = T_enforced - T_commit 

In practice, there may be no single T_enforced.

Different consumers converge at different times.

So we may instead have:

T_enforced(service_i) 

The maximum exposure is:

max_i(T_enforced(service_i)) - T_commit 

This is one of the most important quantities in an authority system.

A revocation architecture is only as strong as its slowest meaningful enforcement point.

Immediate revocation is usually fictional

Systems often document:

revocation takes effect immediately 

What that usually means is:

the authoritative database row changed immediately 

That is not the same thing.

If a signer can continue accepting stale authority for another sixty seconds, then practical revocation latency is sixty seconds.

If a queue worker can execute a command four minutes later without revalidation, then revocation latency is at least four minutes.

The system should measure actual revocation latency, not policy prose.

Online validation

The strongest revocation model is online validation at execution time.

Before performing an economic action:

verify capability check current revocation state check current epoch check current state version execute 

This reduces stale authority.

But it introduces a new dependency.

If the revocation service is unavailable, what happens?

The executor has three broad choices:

fail open fail closed use bounded cached authority 

Each has economic consequences.

Fail open

Fail-open means:

revocation state unavailable capability otherwise valid execute anyway 

This preserves availability.

It also allows revoked authority to execute during control-plane failure.

For irreversible financial actions, this is often unacceptable.

The most dangerous property of fail-open is that the very condition that prevents checking revocation also disables revocation enforcement.

An attacker does not necessarily need to defeat the capability system.

They may only need to isolate its verifier.

Fail closed

Fail-closed means:

revocation state unavailable reject execution 

This protects authority boundaries.

It can also stop legitimate financial activity during control-plane outage.

That may be correct for:

high-value withdrawal treasury movement custody signing 

and excessive for:

low-value internal action 

Revocation availability therefore needs risk-tiered semantics.

Bounded offline authority

A middle ground is bounded offline validation.

Suppose an executor has a cached revocation snapshot valid for:

30 seconds 

It may continue accepting capabilities only while:

now - snapshot_time <= 30s 

After that:

fail closed 

This creates a maximum stale-authority window.

The system can then say something meaningful:

revocation convergence is bounded by 30 seconds under verifier connectivity loss 

That is far stronger than saying:

revocation is eventually consistent 

because eventually is not a financial control objective.

Revocation epochs

One practical mechanism is epoch-based invalidation.

Suppose each account has:

withdrawal_epoch = 17 

Capabilities issued for withdrawals contain:

epoch = 17 

If the account must be frozen:

withdrawal_epoch = 18 

Every capability with epoch 17 becomes stale.

Validation becomes:

capability.epoch == current_epoch 

This can revoke many capabilities without tracking each individually.

Epoch revocation is coarse

Epochs trade precision for efficiency.

If one capability is compromised, incrementing the account epoch may revoke:

every outstanding withdrawal capability 

That may be desirable.

It may also disrupt unrelated operations.

A system can therefore maintain several epochs:

withdrawal_epoch transfer_epoch custody_epoch delegation_epoch 

This reduces blast radius.

The cost is more state and more validation logic.

Epoch caching still has staleness

Suppose an executor cached:

withdrawal_epoch = 17 

The authority source updates:

withdrawal_epoch = 18 

The executor remains unaware.

Epochs simplify invalidation.

They do not eliminate propagation delay.

So the real model remains:

epoch mechanism + freshness bound 

not epoch alone.

Capability expiry as passive revocation

Short-lived capabilities reduce the need for active revocation.

Suppose capability lifetime is:

20 seconds 

Even if a revocation message is lost, stale authority disappears soon.

This is useful where capabilities can be regenerated cheaply.

The upper bound on stale authority becomes approximately:

capability lifetime 

assuming execution validates expiration correctly.

Lifetime versus operational latency

Capability lifetime cannot be chosen independently of workflow latency.

Suppose:

capability TTL = 20s queue latency p99 = 18s execution setup = 5s 

Legitimate requests will frequently expire before execution.

Teams then increase TTL.

Eventually:

TTL = 30 minutes 

and active revocation becomes critical again.

Capability lifetime must therefore be tied to actual execution latency and economic consequence.

Queue boundaries are revocation traps

Queues are particularly dangerous.

Suppose capability C is validated by Service A.

Service A publishes:

ExecuteWithdrawal { operation_id = W } 

The queue delivers it five minutes later.

If the worker executes because:

message came from trusted queue 

then revocation cannot stop the operation after enqueue.

Authority was effectively converted into a durable command.

This is authority laundering through asynchronous infrastructure.

Revalidate at the irreversible boundary

A strong principle is:

validate authority as late as possible before irreversible effect 

Service A may perform early validation.

The final executor should validate again.

For example:

API validation -> orchestration -> queue -> worker revalidation -> custody revalidation -> external execution 

Repeated validation is not redundant.

Each boundary operates at a later point in the authority lifecycle.

Durable authorization versus durable intent

Queued messages should ideally preserve intent, not final authority.

For example:

WithdrawalIntent { operation_id } 

The worker loads current authorization state before execution.

Compare that with:

ExecuteWithdrawalUnconditionally { amount destination } 

The first is revocable.

The second is effectively an already-exercised permission waiting for CPU time.

Reservation complicates revocation

Suppose capability C has already reserved 500k.

Then the account is frozen.

Should revocation release the reservation?

If no execution has begun:

yes, probably 

If execution may already have been submitted externally:

not safely 

The capability lifecycle therefore matters.

For example:

Issued Reserved Executing ExecutionUnknown Consumed 

Revocation behavior depends on the current state.

Revocation by lifecycle state

A possible model:

Issued: revoke immediately Reserved: revoke and release reservation if execution has not started Executing: prevent downstream steps where possible do not assume rollback ExecutionUnknown: freeze authority state reconcile external outcome Consumed: revocation has no preventive effect compensation may be required 

This is much more realistic than:

revoked = true 

The point of no return

Every financial workflow has a point beyond which revocation cannot guarantee prevention.

Call it:

PONR = point of no return 

Before PONR:

revocation can prevent external effect 

After PONR:

revocation may only prevent later effects or trigger compensation 

The exact point depends on the rail.

For a blockchain transaction:

before signature before broadcast after broadcast after inclusion 

have different revocability.

For a bank transfer:

before submission after submission before bank acceptance after booking 

again differ.

Revocability should be explicit

The capability state should expose:

revocation_class 

For example:

fully_revocable revocable_until_submission revocable_until_external_acceptance non_revocable 

This helps risk and operations reason about what revocation can still accomplish.

Revocation after submission

Suppose a transaction has been submitted but not confirmed.

The system receives a revocation request.

Possible outcomes include:

provider cancellation succeeds provider cancellation fails provider does not support cancellation outcome unknown 

The revocation workflow itself becomes a distributed transaction.

It needs:

attempt identity evidence timeout semantics reconciliation 

because the system may not know whether cancellation actually happened.

Revocation is another economic operation

This is a useful conceptual shift.

Revocation is not merely metadata.

It can create:

reservation release cancellation request compensation obligation customer restriction authority graph invalidation 

Therefore revocation should often have its own operation identity:

revocation_id 

and state machine.

Revocation state machine

For example:

Requested | v Committed | v PropagationInProgress / \ / \ v v Enforced Partial | v Reconciled 

A final state may be:

FullyEnforced PartiallyEnforced CompensationRequired 

This is much more informative than a timestamp column.

Descendant capabilities

Delegation makes revocation harder.

Suppose:

C0 -> C1 -> C2 

If C0 is revoked, what happens to C1 and C2?

Usually:

they should become invalid 

because their authority derives from C0.

This means revocation propagates through the authority graph.

Transitive invalidation

Let:

Parent(C1) = C0 Parent(C2) = C1 

If:

Revoked(C0) 

then:

Invalid(C1) Invalid(C2) 

unless the model explicitly defines delegation as authority transfer rather than derivative authority.

This semantic choice must be explicit.

Derived authority versus transferred authority

There are two very different delegation models.

Derived authority:

child depends on parent remaining valid 

Transferred authority:

child becomes independently valid parent gives up some capacity 

These have different revocation semantics.

If authority is transferred:

revoking parent 

may not revoke already transferred child authority.

This can be desirable for isolated execution domains.

It can also surprise operators.

The architecture must define which model it uses.

Revocation graph cost

A naive system may recursively traverse every descendant whenever a root is revoked.

For large authority graphs, that can be expensive.

Epochs offer one compression mechanism.

For example, descendants reference:

authority_epoch = 44 

Revoking the root increments:

authority_epoch = 45 

Every descendant becomes invalid without explicit traversal.

But again, consumers must observe the new epoch.

Scope epochs

A useful pattern is tying epochs to authority scopes.

For example:

root_authority_epoch account_epoch asset_epoch operation_epoch 

A capability carries the relevant epoch vector:

epochs: account = 17 withdrawal = 9 

Validation requires all relevant values to match.

This supports broad or narrow revocation.

Capability revocation lists

Individual capabilities may still need direct revocation.

A revocation list can store:

capability_id revoked_at reason 

This works for small or high-value sets.

At high scale, online lookup for every operation can become expensive.

Caching reintroduces staleness.

Nothing escapes physics merely because we named the table revocations.

Revocation bloom filters

One optimization is distributing compact revocation structures.

For example, a Bloom filter can answer:

possibly revoked? 

False positives are possible.

False negatives should not be.

A consumer seeing:

not present 

can proceed according to snapshot freshness.

A consumer seeing:

possibly present 

performs authoritative lookup.

This can reduce online validation load.

But the filter itself needs:

version generated_at valid_until 

or it becomes another stale trust artifact.

Revocation snapshots

Execution services may consume signed snapshots:

RevocationSnapshot: sequence generated_at valid_until epoch_map revoked_capability_set_root 

The snapshot can be cryptographically authenticated.

Consumers reject snapshots older than policy allows.

This creates bounded offline enforcement.

Sequence numbers

Revocation updates should be ordered.

Suppose a consumer sees snapshots:

101 102 100 

It must not regress to 100.

Enforce:

new_sequence >= current_sequence 

for monotonic control-plane state.

Otherwise delayed messages can resurrect old authority.

Authority resurrection

This is a particularly dangerous failure mode.

Suppose:

epoch 17 valid epoch 18 revoked old capabilities 

A stale cache restore accidentally reloads:

epoch 17 

Capabilities thought dead become executable again.

Revocation state must therefore be monotonic.

The control plane should never accept lower revocation versions.

Rollback safety

Infrastructure rollback is normal.

Authorization rollback is not.

Suppose a deployment rollback restores an older database snapshot.

If capability epochs or consumed nonces roll backward, the platform may resurrect:

revoked authority consumed authority 

This can create direct economic loss.

Security-critical monotonic state should be separated from ordinary rollback semantics.

Consumption state is revocation-related

A consumed capability is effectively permanently revoked from future use.

Therefore capability consumption state has the same monotonicity requirements as revocation.

For one-shot capability C:

Issued -> Consumed 

must never become:

Consumed -> Issued 

even after disaster recovery.

Backup restoration

Disaster recovery must therefore reconcile:

capability issuance consumption revocation external execution 

Restoring an older capability database without replaying later authority events is unsafe.

The system may need an append-only authority log whose history survives ordinary database snapshots.

Authority event log

For example:

CapabilityIssued CapabilityDelegated CapabilityReserved CapabilityConsumed CapabilityRevoked EpochIncremented 

These events form the durable authority history.

Materialized capability state can be rebuilt from them.

This resembles event sourcing, but the safety motivation is monotonic authority reconstruction.

Multi-region revocation

Now consider multiple regions.

Region A commits:

revoke C 

Region B is partitioned.

Region B still has:

C valid 

Should Region B continue executing?

This is a consistency decision.

For high-value financial authority, allowing execution under stale authorization may be worse than losing availability.

This is where distributed systems theory stops being a diagram and starts having a P&L.

CP versus AP for authority

Under network partition, a system can prioritize:

availability 

or:

current revocation consistency 

It cannot always guarantee both.

For high-risk authority, the system may choose:

partition -> stop execution 

For lower-risk authority:

partition -> allow bounded stale capability 

The policy should be explicit by action class.

Region leases

One mechanism is granting regions short-lived authority leases.

For example:

Region B may execute withdrawals until 14:05 under revocation sequence >= 991 

If it cannot renew the lease:

execution stops 

This converts indefinite partition risk into bounded partition risk.

Lease semantics

A lease may contain:

region_id authority_scope max_value revocation_sequence_floor issued_at expires_at 

Region B can execute only while:

now < expires_at AND local_revocation_sequence >= sequence_floor 

This gives central control a bounded stale-authority window.

Lease value limits

Time alone may not be enough.

A partitioned region might execute enormous value during a short lease.

So a lease can also carry:

maximum aggregate amount 

For example:

5-minute lease max spend = 1M 

The risk is bounded by both:

time value 

Revocation budget

This suggests a useful concept:

revocation budget 

The maximum economic authority that may remain executable while revocation information is stale.

For a region:

revocation_budget = lease_capacity 

For a service:

revocation_budget = outstanding short-lived capabilities 

The platform should know how much value could still escape after a revocation decision.

Value-at-stale-authority

A useful metric is:

value_at_stale_authority 

Meaning:

maximum economic effect currently executable using authority that has not refreshed revocation state within target freshness 

If this number grows large, the architecture has a revocation problem even if no incident has occurred.

Revocation latency distribution

The platform should measure:

decision-to-commit commit-to-publication publication-to-observation observation-to-enforcement 

Then report:

p50 p95 p99 max 

for revocation convergence.

Security statements can then become concrete:

99% of withdrawal revocations reach all active execution nodes within 4.2 seconds 

That is operationally meaningful.

Maximum matters

Averages are not enough.

One worker that remains stale for twenty minutes may be sufficient for loss.

Revocation systems care deeply about tails.

A useful SLO might be:

no executor may use revocation state older than 15 seconds for high-value withdrawals 

That is stronger than:

average revocation delay < 2s 

Revocation acknowledgments

Execution nodes can acknowledge applied revocation state.

For example:

ExecutorAck: executor_id revocation_sequence observed_at 

The control plane can see which nodes are stale.

It may then quarantine those nodes from receiving new economic work.

Stale executor quarantine

Suppose Worker 17 has not advanced beyond:

revocation sequence 991 

while current is:

1004 

The scheduler can stop assigning sensitive operations to Worker 17.

This prevents stale authority from remaining silently active.

Revocation-aware scheduling

The scheduler should consider:

worker revocation freshness worker policy version worker key state 

before dispatching high-value work.

Execution capacity is therefore partly a function of control-plane freshness.

Cached authorization decisions

Another trap is caching:

account_allowed = true 

for ten minutes.

The account is frozen after one minute.

The cache keeps returning true.

The revocation system may be perfectly correct.

The authorization cache bypasses it.

Revocation analysis must include every derived authorization cache.

Cache invalidation really is authorization invalidation

The old joke about cache invalidation becomes considerably less amusing around money.

Any cache that stores:

approved allowed withdrawable trusted 

holds economic authority.

Its TTL is part of revocation latency.

That should be documented and measured as such.

Negative caching

Even negative authorization can cause issues.

Suppose an account is temporarily blocked and the block is lifted.

A stale negative cache continues rejecting valid operations.

This is economically safer than stale positive authority but still operationally relevant.

The system may intentionally use asymmetric TTLs:

positive authorization TTL = 5s negative authorization TTL = 30s 

because stale permission is more dangerous than stale denial.

Asymmetric caching

This asymmetry is useful across security.

For example:

allow cache: short lifetime deny cache: longer lifetime 

The system favors false denial over false authorization where consequences justify it.

Signer revocation

Custody systems deserve special attention.

Suppose a signing service receives:

sign transaction T 

with capability C.

While the signing protocol is running, C is revoked.

Should the signer finish?

The answer depends on protocol stage.

Before any irreversible signature material is produced:

abort 

After a complete valid signature exists:

revocation may be too late 

because the artifact can potentially be submitted elsewhere.

Signature material is authority

Once a valid transaction signature exists, the capability has effectively been transformed into a narrower but potentially irreversible artifact.

Revoking the original capability may not revoke the signature.

This is another point of no return.

Therefore high-assurance signing systems may:

bind signature to exact transaction avoid exposing raw reusable signing authority submit immediately through controlled path 

The objective is to minimize the interval where valid but unsubmitted signed transactions exist.

Signing and broadcast coupling

One architecture:

authorize -> sign -> broadcast 

with separate services creates a signed-artifact gap.

Another approach tightly couples:

sign-and-submit 

under one bounded operation.

This reduces revocation flexibility after signing but also reduces the number of places where executable signed artifacts can leak.

There is no free option.

Blockchain cancellation

Some blockchain workflows support replacement transactions.

Revocation after broadcast may attempt:

replace transaction cancel nonce increase fee 

But cancellation is probabilistic until the replacement becomes canonical.

The correct state is:

cancellation_attempted 

not:

cancelled 

until evidence proves the outcome.

Bank cancellation

Similarly, a bank API may return:

cancellation request accepted 

This does not necessarily mean:

transfer cancelled 

The cancellation request itself requires finality semantics.

Revocation inherits all the evidence problems of the operation it tries to stop.

Compensation boundary

Once an action cannot be prevented, revocation becomes a recovery trigger.

Suppose:

capability revoked transaction already settled 

The system should not keep retrying preventive revocation.

It should transition:

prevention -> compensation 

Possible actions include:

create receivable freeze account recover funds reverse internal credit trigger legal or compliance workflow 

Prevention and compensation should not be conflated

A common incident mistake is continuing to call an operation:

revoked 

even after the financial effect occurred.

Better states are:

revocation_requested revocation_enforced_before_execution revocation_too_late compensation_required compensation_complete 

These describe reality.

Revocation provenance

Every revocation should record:

who requested it why which authority was targeted which evidence triggered it when it became authoritative which execution points acknowledged it whether any effects escaped 

For example:

RevocationDecision: revocation_id capability_id reason evidence_refs actor committed_at policy_digest 

Then:

RevocationEnforcement: executor revocation_sequence enforced_at 

This creates an audit trail of convergence.

Revocation cause matters

Not all revocations are equivalent.

Examples:

customer cancellation fraud detection sanctions update key compromise policy change operator correction provider failure 

The cause may change required response.

Key compromise may require revoking an entire authority subtree.

Customer cancellation may target one operation.

Sanctions action may require broader freezing.

The revocation class should therefore influence propagation.

Key compromise revocation

Suppose issuer key K is compromised.

The system may need to invalidate:

all capabilities issued by K during interval [T1, T2] 

This is much broader than individual capability revocation.

The authority graph helps identify affected descendants.

Time uncertainty under compromise

The exact compromise time may be unknown.

Suppose evidence shows:

compromise occurred sometime between 12:00 and 14:00 

The platform may need to treat all capabilities issued during that interval as suspect.

This is another epistemic-capacity problem.

Uncertainty about compromise expands the revocation set.

Revocation storms

A large incident may require revoking millions of capabilities simultaneously.

For example:

issuer compromise provider compromise account class freeze 

Can the revocation system handle this?

Individual database updates may not scale.

Epoch invalidation becomes valuable here.

One atomic epoch increment can invalidate an entire authority class.

Revocation scalability

The system should stress-test:

100 individual revocations 100k revocations global epoch change regional partition during mass revocation 

because the security mechanism must work precisely when the system is under abnormal load.

Control-plane overload

A revocation storm can overload:

message buses cache invalidation signer lookups authorization APIs 

If overload causes fail-open behavior, the system fails exactly backward.

Security control planes should be provisioned for emergency peaks, not normal averages.

Revocation priority

Not every revocation has the same urgency.

A possible priority hierarchy:

critical: compromised signing authority high: fraud-confirmed account medium: customer cancellation low: policy cleanup 

Propagation infrastructure may prioritize critical revocations.

This reduces time-to-enforcement for the highest-value threats.

Revocation preemption

A high-priority revocation should be able to overtake queued low-priority work.

For example:

signing requests queue length = 5000 

A fraud freeze arrives.

The revocation should not sit behind those 5000 jobs.

Security events require priority channels.

Kill switches

At the highest level, systems often need coarse emergency controls.

Examples:

disable all external withdrawals disable asset X disable provider Y disable custody signer group Z 

These are coarse revocation mechanisms.

They sacrifice availability for containment.

They should be:

simple strongly authenticated independently available well tested 

A kill switch nobody has tested is a decorative control.

Kill-switch independence

If the normal control plane is compromised, the emergency mechanism should not rely entirely on the same trust path.

For example, an emergency withdrawal halt may require:

separate credentials separate approval path independent signing authority 

Otherwise attacker control of the normal authority plane may include control of its own revocation.

Revocation and formal methods

Several useful properties can be formalized.

For example:

Revoked(C, t) AND ExecutionStarts(A, t') AND t' > t + Delta 

should imply:

not AuthorizedBy(A, C) 

where Delta is the maximum permitted revocation propagation bound.

This is a bounded-staleness safety property.

Descendant invalidation property

For derivative delegation:

Descendant(C_child, C_parent) AND Revoked(C_parent) 

implies:

Invalid(C_child) 

after bounded convergence.

No resurrection

For revocation sequence r:

AppliedSequence(node, t+1) >= AppliedSequence(node, t) 

This prevents stale state rollback.

Consumed authority monotonicity

For one-shot capabilities:

Consumed(C, t) 

implies:

Consumed(C, t') 

for all:

t' > t 

The system must never reconstruct C as unused.

Revocation-before-effect

For operations whose execution has not passed the point of no return:

RevocationCommitted(C) before PONR(operation) 

should imply:

Related posts