DEV Community

Cover image for Revocation Under Partial Failure: Killing Financial Authority in a Distributed System
Mayckon Giovani
Mayckon Giovani

Posted on

Revocation Under Partial Failure: Killing Financial Authority in a Distributed System

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?
Enter fullscreen mode Exit fullscreen mode

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?
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The capability is issued at 14:00.

It propagates through:

API
    ->
orchestrator
    ->
queue
    ->
worker
    ->
custody
Enter fullscreen mode Exit fullscreen mode

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

The system commits:

revoked(C) = true
Enter fullscreen mode Exit fullscreen mode

at 14:03:01.

But the capability may already exist in several places:

orchestrator memory
queue payload
worker local cache
custody request
retry buffer
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Then:

revocation_exposure_window =
    T_enforced - T_commit
Enter fullscreen mode Exit fullscreen mode

In practice, there may be no single T_enforced.

Different consumers converge at different times.

So we may instead have:

T_enforced(service_i)
Enter fullscreen mode Exit fullscreen mode

The maximum exposure is:

max_i(T_enforced(service_i)) - T_commit
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

What that usually means is:

the authoritative database row changed immediately
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Each has economic consequences.

Fail open

Fail-open means:

revocation state unavailable
capability otherwise valid
execute anyway
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

and excessive for:

low-value internal action
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

It may continue accepting capabilities only while:

now - snapshot_time <= 30s
Enter fullscreen mode Exit fullscreen mode

After that:

fail closed
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

That is far stronger than saying:

revocation is eventually consistent
Enter fullscreen mode Exit fullscreen mode

because eventually is not a financial control objective.

Revocation epochs

One practical mechanism is epoch-based invalidation.

Suppose each account has:

withdrawal_epoch = 17
Enter fullscreen mode Exit fullscreen mode

Capabilities issued for withdrawals contain:

epoch = 17
Enter fullscreen mode Exit fullscreen mode

If the account must be frozen:

withdrawal_epoch = 18
Enter fullscreen mode Exit fullscreen mode

Every capability with epoch 17 becomes stale.

Validation becomes:

capability.epoch == current_epoch
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The authority source updates:

withdrawal_epoch = 18
Enter fullscreen mode Exit fullscreen mode

The executor remains unaware.

Epochs simplify invalidation.

They do not eliminate propagation delay.

So the real model remains:

epoch mechanism
+
freshness bound
Enter fullscreen mode Exit fullscreen mode

not epoch alone.

Capability expiry as passive revocation

Short-lived capabilities reduce the need for active revocation.

Suppose capability lifetime is:

20 seconds
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Legitimate requests will frequently expire before execution.

Teams then increase TTL.

Eventually:

TTL = 30 minutes
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

The queue delivers it five minutes later.

If the worker executes because:

message came from trusted queue
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Service A may perform early validation.

The final executor should validate again.

For example:

API validation
    ->
orchestration
        ->
queue
            ->
worker revalidation
                ->
custody revalidation
                    ->
external execution
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

The worker loads current authorization state before execution.

Compare that with:

ExecuteWithdrawalUnconditionally {
    amount
    destination
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

If execution may already have been submitted externally:

not safely
Enter fullscreen mode Exit fullscreen mode

The capability lifecycle therefore matters.

For example:

Issued
Reserved
Executing
ExecutionUnknown
Consumed
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

This is much more realistic than:

revoked = true
Enter fullscreen mode Exit fullscreen mode

The point of no return

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

Call it:

PONR = point of no return
Enter fullscreen mode Exit fullscreen mode

Before PONR:

revocation can prevent external effect
Enter fullscreen mode Exit fullscreen mode

After PONR:

revocation may only prevent later effects
or trigger compensation
Enter fullscreen mode Exit fullscreen mode

The exact point depends on the rail.

For a blockchain transaction:

before signature
before broadcast
after broadcast
after inclusion
Enter fullscreen mode Exit fullscreen mode

have different revocability.

For a bank transfer:

before submission
after submission
before bank acceptance
after booking
Enter fullscreen mode Exit fullscreen mode

again differ.

Revocability should be explicit

The capability state should expose:

revocation_class
Enter fullscreen mode Exit fullscreen mode

For example:

fully_revocable
revocable_until_submission
revocable_until_external_acceptance
non_revocable
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The revocation workflow itself becomes a distributed transaction.

It needs:

attempt identity
evidence
timeout semantics
reconciliation
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Therefore revocation should often have its own operation identity:

revocation_id
Enter fullscreen mode Exit fullscreen mode

and state machine.

Revocation state machine

For example:

Requested
    |
    v
Committed
    |
    v
PropagationInProgress
   /   \
  /     \
 v       v
Enforced  Partial
            |
            v
        Reconciled
Enter fullscreen mode Exit fullscreen mode

A final state may be:

FullyEnforced
PartiallyEnforced
CompensationRequired
Enter fullscreen mode Exit fullscreen mode

This is much more informative than a timestamp column.

Descendant capabilities

Delegation makes revocation harder.

Suppose:

C0
    ->
C1
    ->
C2
Enter fullscreen mode Exit fullscreen mode

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

Usually:

they should become invalid
Enter fullscreen mode Exit fullscreen mode

because their authority derives from C0.

This means revocation propagates through the authority graph.

Transitive invalidation

Let:

Parent(C1) = C0
Parent(C2) = C1
Enter fullscreen mode Exit fullscreen mode

If:

Revoked(C0)
Enter fullscreen mode Exit fullscreen mode

then:

Invalid(C1)
Invalid(C2)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Transferred authority:

child becomes independently valid
parent gives up some capacity
Enter fullscreen mode Exit fullscreen mode

These have different revocation semantics.

If authority is transferred:

revoking parent
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Revoking the root increments:

authority_epoch = 45
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

A capability carries the relevant epoch vector:

epochs:
    account = 17
    withdrawal = 9
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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?
Enter fullscreen mode Exit fullscreen mode

False positives are possible.

False negatives should not be.

A consumer seeing:

not present
Enter fullscreen mode Exit fullscreen mode

can proceed according to snapshot freshness.

A consumer seeing:

possibly present
Enter fullscreen mode Exit fullscreen mode

performs authoritative lookup.

This can reduce online validation load.

But the filter itself needs:

version
generated_at
valid_until
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

It must not regress to 100.

Enforce:

new_sequence >= current_sequence
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

A stale cache restore accidentally reloads:

epoch 17
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

must never become:

Consumed -> Issued
Enter fullscreen mode Exit fullscreen mode

even after disaster recovery.

Backup restoration

Disaster recovery must therefore reconcile:

capability issuance
consumption
revocation
external execution
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Region B is partitioned.

Region B still has:

C valid
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

or:

current revocation consistency
Enter fullscreen mode Exit fullscreen mode

It cannot always guarantee both.

For high-risk authority, the system may choose:

partition -> stop execution
Enter fullscreen mode Exit fullscreen mode

For lower-risk authority:

partition -> allow bounded stale capability
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

If it cannot renew the lease:

execution stops
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Region B can execute only while:

now < expires_at
AND local_revocation_sequence >= sequence_floor
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

For example:

5-minute lease
max spend = 1M
Enter fullscreen mode Exit fullscreen mode

The risk is bounded by both:

time
value
Enter fullscreen mode Exit fullscreen mode

Revocation budget

This suggests a useful concept:

revocation budget
Enter fullscreen mode Exit fullscreen mode

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

For a region:

revocation_budget =
    lease_capacity
Enter fullscreen mode Exit fullscreen mode

For a service:

revocation_budget =
    outstanding short-lived capabilities
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Meaning:

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

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
Enter fullscreen mode Exit fullscreen mode

Then report:

p50
p95
p99
max
Enter fullscreen mode Exit fullscreen mode

for revocation convergence.

Security statements can then become concrete:

99% of withdrawal revocations
reach all active execution nodes
within 4.2 seconds
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

That is stronger than:

average revocation delay < 2s
Enter fullscreen mode Exit fullscreen mode

Revocation acknowledgments

Execution nodes can acknowledge applied revocation state.

For example:

ExecutorAck:
    executor_id
    revocation_sequence
    observed_at
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

while current is:

1004
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

After a complete valid signature exists:

revocation may be too late
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Signing and broadcast coupling

One architecture:

authorize
    ->
sign
        ->
broadcast
Enter fullscreen mode Exit fullscreen mode

with separate services creates a signed-artifact gap.

Another approach tightly couples:

sign-and-submit
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

But cancellation is probabilistic until the replacement becomes canonical.

The correct state is:

cancellation_attempted
Enter fullscreen mode Exit fullscreen mode

not:

cancelled
Enter fullscreen mode Exit fullscreen mode

until evidence proves the outcome.

Bank cancellation

Similarly, a bank API may return:

cancellation request accepted
Enter fullscreen mode Exit fullscreen mode

This does not necessarily mean:

transfer cancelled
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The system should not keep retrying preventive revocation.

It should transition:

prevention
    ->
compensation
Enter fullscreen mode Exit fullscreen mode

Possible actions include:

create receivable
freeze account
recover funds
reverse internal credit
trigger legal or compliance workflow
Enter fullscreen mode Exit fullscreen mode

Prevention and compensation should not be conflated

A common incident mistake is continuing to call an operation:

revoked
Enter fullscreen mode Exit fullscreen mode

even after the financial effect occurred.

Better states are:

revocation_requested
revocation_enforced_before_execution
revocation_too_late
compensation_required
compensation_complete
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

For example:

RevocationDecision:
    revocation_id
    capability_id
    reason
    evidence_refs
    actor
    committed_at
    policy_digest
Enter fullscreen mode Exit fullscreen mode

Then:

RevocationEnforcement:
    executor
    revocation_sequence
    enforced_at
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

These are coarse revocation mechanisms.

They sacrifice availability for containment.

They should be:

simple
strongly authenticated
independently available
well tested
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

should imply:

not AuthorizedBy(A, C)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

implies:

Invalid(C_child)
Enter fullscreen mode Exit fullscreen mode

after bounded convergence.

No resurrection

For revocation sequence r:

AppliedSequence(node, t+1)
>=
AppliedSequence(node, t)
Enter fullscreen mode Exit fullscreen mode

This prevents stale state rollback.

Consumed authority monotonicity

For one-shot capabilities:

Consumed(C, t)
Enter fullscreen mode Exit fullscreen mode

implies:

Consumed(C, t')
Enter fullscreen mode Exit fullscreen mode

for all:

t' > t
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

should imply:

ExternalEffect(operation) = false
Enter fullscreen mode Exit fullscreen mode

subject to the documented propagation bound.

This is a meaningful testable safety objective.

A Rust sketch

A capability might carry epoch state:

#[derive(Debug, Clone)]
pub struct Capability {
    pub capability_id: String,
    pub subject_id: String,
    pub action: Action,
    pub account_epoch: u64,
    pub action_epoch: u64,
    pub expires_at: u64,
}

#[derive(Debug, Clone)]
pub struct RevocationView {
    pub account_epoch: u64,
    pub action_epoch: u64,
    pub sequence: u64,
    pub observed_at: u64,
}
Enter fullscreen mode Exit fullscreen mode

Validation:

pub fn validate(
    capability: &Capability,
    view: &RevocationView,
    now: u64,
    max_view_age: u64,
) -> Result<(), ValidationError> {
    if now > capability.expires_at {
        return Err(ValidationError::Expired);
    }

    if now.saturating_sub(view.observed_at) > max_view_age {
        return Err(ValidationError::RevocationViewStale);
    }

    if capability.account_epoch != view.account_epoch {
        return Err(ValidationError::AccountAuthorityRevoked);
    }

    if capability.action_epoch != view.action_epoch {
        return Err(ValidationError::ActionAuthorityRevoked);
    }

    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

The interesting part is not the code.

It is that:

max_view_age
Enter fullscreen mode Exit fullscreen mode

is now an explicit security parameter.

Revocation as a bounded-consistency contract

This gives us a more honest system statement.

Not:

revocations are immediate
Enter fullscreen mode Exit fullscreen mode

but:

high-value withdrawal authority
cannot remain executable
more than 10 seconds after
authoritative revocation commit,
assuming at least one control-plane path remains available
Enter fullscreen mode Exit fullscreen mode

That is specific.

It can be measured.

It can be violated.

It can therefore be engineered.

Revocation SLOs

Possible operational objectives include:

p99 revocation propagation < 5s

max stale revocation view < 10s

100% high-value executors fail closed
after revocation view expiry

zero authority resurrection
after snapshot restore
Enter fullscreen mode Exit fullscreen mode

These are much stronger than:

revocation service uptime = 99.99%
Enter fullscreen mode Exit fullscreen mode

A revocation service can have excellent uptime and still propagate too slowly to protect money.

Revocation observability

Useful metrics include:

current revocation sequence
executor sequence lag
maximum revocation age
value behind stale executors
active revoked-but-unexpired capabilities
revocation propagation p99
execution-unknown value after revocation
descendant capabilities pending invalidation
Enter fullscreen mode Exit fullscreen mode

One particularly important metric is:

value_at_revocation_risk
Enter fullscreen mode Exit fullscreen mode

Meaning:

maximum economic effect
still executable by authority
that should already be dead
Enter fullscreen mode Exit fullscreen mode

That number should be aggressively boring.

Testing revocation

Unit tests are insufficient.

The system should inject:

delayed revocation event
worker partition
stale cache
queue backlog
database rollback
region isolation
signer offline
duplicate revocation
out-of-order epoch update
Enter fullscreen mode Exit fullscreen mode

Then verify economic outcomes.

For example:

revoke capability
partition one worker
wait beyond allowed stale window
attempt withdrawal through worker
Enter fullscreen mode Exit fullscreen mode

Expected:

rejected
Enter fullscreen mode Exit fullscreen mode

Not because the worker learned the revocation.

Because it failed to refresh within the permitted bound.

This distinction is fundamental.

Revocation under total control-plane loss

Suppose every revocation source is unavailable.

The system cannot know whether any existing capability has been revoked.

What should happen?

For high-value irreversible authority:

stop execution when local lease expires
Enter fullscreen mode Exit fullscreen mode

For low-value reversible actions:

possibly continue inside bounded exposure
Enter fullscreen mode Exit fullscreen mode

The system should degrade by economic consequence.

Revocation debt

If some executors are temporarily offline, revocation may not be applied immediately.

When they return, they must catch up before processing new work.

Until then, they carry revocation debt.

A node coming online should:

load latest revocation state
verify monotonic sequence
refresh policy
then accept economic work
Enter fullscreen mode Exit fullscreen mode

Not:

start worker
process backlog
eventually refresh auth
Enter fullscreen mode Exit fullscreen mode

That ordering matters.

Startup safety

A newly started process with no revocation state should begin:

unauthorized to execute
Enter fullscreen mode Exit fullscreen mode

until it obtains sufficiently fresh authority state.

Default-deny at startup prevents cold nodes from becoming revocation bypasses.

Revocation and long-running workflows

Some operations last minutes or hours.

Should authority be checked only at start?

Probably not.

Long-running workflows may require checkpoints.

For example:

batch settlement:
    prepare
    reserve
    sign
    submit
Enter fullscreen mode Exit fullscreen mode

Revocation may be checked before each irreversible phase.

Authority becomes phase-scoped.

Phase capabilities

Instead of one long-lived capability:

execute settlement
Enter fullscreen mode Exit fullscreen mode

issue:

prepare capability
reserve capability
sign capability
submit capability
Enter fullscreen mode Exit fullscreen mode

Each later phase requires stronger or fresher authority.

This reduces how much stale permission survives through long workflows.

Escalating proof near irreversibility

A general principle emerges:

As an operation approaches irreversible external effect:

authority should become
narrower,
fresher,
and more strongly validated.
Enter fullscreen mode Exit fullscreen mode

Early planning stages may tolerate broader, cached authority.

Final execution should not.

Revocation and human operators

Manual emergency revocation matters too.

An operator may need to freeze:

one account
one asset
one provider
all withdrawals
Enter fullscreen mode Exit fullscreen mode

The interface should make scope explicit.

A button labeled:

Disable
Enter fullscreen mode Exit fullscreen mode

is not enough.

Disable what?

For whom?

Which already-issued authority becomes invalid?

Which in-flight operations continue?

Operational tooling should surface those semantics.

Human revocation confirmation

For high-impact actions, the system may show:

This action will invalidate:
    14,882 active capabilities
    3.2M of reserved withdrawal authority
    412 in-flight operations

92 operations are past the point of no return.
Enter fullscreen mode Exit fullscreen mode

Now the operator understands the actual effect.

This is much better than:

Are you sure?
Enter fullscreen mode Exit fullscreen mode

which remains one of software's more ambitious attempts at risk management.

Conclusion

Revocation in distributed financial systems is not a boolean transition.

Authority may already have propagated through services, queues, caches, workers, signers, regions, and derived capabilities before revocation begins.

Once revocation is committed, the system enters a race.

Can invalidation reach every relevant execution point before stale authority produces an irreversible effect?

A resilient architecture therefore treats revocation as a distributed protocol.

It defines:

where authority exists
how fresh revocation state must be
which actions fail closed
how epochs invalidate authority
how descendants inherit revocation
where the point of no return lies
how stale executors are quarantined
how unknown execution outcomes are reconciled
Enter fullscreen mode Exit fullscreen mode

Most importantly, it distinguishes prevention from compensation.

Before the point of no return, revocation should stop authority.

After it, revocation cannot rewrite history.

It must trigger recovery.

The useful invariant is not:

revoked == true
Enter fullscreen mode Exit fullscreen mode

It is:

After authoritative revocation,
no economically significant effect
may be created by that authority
beyond the system's explicitly bounded
revocation exposure window.
Enter fullscreen mode Exit fullscreen mode

That window has two dimensions:

time
and
value
Enter fullscreen mode Exit fullscreen mode

A mature financial system knows both.

Because authority that should be dead but can still move money is not merely stale state.

It is live risk.

Top comments (1)

Collapse
 
arhancanli profile image
Arhan Canli •

The line "revocation exposure = max_i(T_enforced(service_i)) − T_commit" is the right quantity, but I think it undercounts. A validity check followed by an irreversible effect has its own window, time of check to time of use. If the custody call validates the capability at T and the withdrawal takes a retry loop or a queue hop to land at T + d, the exposure for that execution is the cache or epoch staleness plus d, and d is unbounded when the signer retries. So the bounded-offline rule of "snapshot age ≤ 30 s" gives a 30 s bound only if the check happens in the same step that makes the effect irreversible, or the effect carries the epoch it was validated against and the settlement side rejects a stale one.

Second, capability.epoch == current_epoch treats a capability from a newer epoch than the verifier's snapshot as stale. That's the safe direction for a lagging verifier, but the result is rejection of legitimately issued capabilities right after any epoch bump, so the unavailable-vs-unsafe trade shows up there as well as at the revocation service. Do you log the two rejection reasons separately (older than current vs newer than snapshot)? The second count is a direct measure of verifier lag.

(Reasoned from the article, not run.)