Dev.to Security ๐Ÿ” Cybersecurity ๐Ÿ‘ 0 ๐Ÿ“– 26 min read

Economic Capability Security in Distributed Financial Systems: Delegation, Replay, Attenuation, and the Confused Deputy

Abstract Financial authorization is usually modeled through identities and roles. A user is authenticated. A service has a role. An operator belongs to a group. A backend checks whether the caller may perform an actio

Abstract

Financial authorization is usually modeled through identities and roles.

A user is authenticated. A service has a role. An operator belongs to a group. A backend checks whether the caller may perform an action.

This model works until economic authority becomes distributed.

A payment orchestrator may be allowed to spend from a treasury account, but only for a specific settlement. A custody service may sign a transaction, but only within an approved amount, asset, destination, and policy window. A downstream service may receive permission to execute a withdrawal without receiving authority to create another withdrawal. A merchant may delegate refund authority to a processor while retaining the ability to revoke it. A risk engine may authorize 500,000 units of provisional exposure without granting permission to consume another 500,000 simply because the same request is replayed.

These are capability problems.

An economic capability is not merely proof that some state is true. It is bounded authority to cause a specific financial state transition.

Once financial authority is represented explicitly, an entire class of security questions becomes visible: replay, delegation, attenuation, confused-deputy attacks, capability laundering, stale authority, double consumption, issuer compromise, transitive privilege expansion, and revocation under partial failure.

This article develops a capability-security model for distributed financial infrastructure. We examine how economic authority should be scoped, delegated, attenuated, consumed, revoked, and audited without allowing downstream systems to manufacture stronger authority than they received.

The core safety requirement is simple:

Authority may move.

It must never grow accidentally.

Authentication is not authorization

Consider a withdrawal endpoint:

POST /withdrawals

The request arrives with an authenticated user.

The backend checks:

user.is_authenticated == true

Then:

user.balance >= amount

Then it executes the withdrawal.

This looks like authorization.

It is mostly authentication plus a balance check.

The system still needs to answer:

Is this user allowed to withdraw this asset?

To this destination?

At this amount?

At this moment?

Using which source of funds?

Under which settlement state?

After which compliance decision?

Against which liquidity allocation?

How many times may the authorization be exercised?

Can another service exercise it on the user's behalf?

Can that service delegate it again?

Authentication answers:

Who is making the request?

Capability security answers:

What exact economic authority does this caller possess?

Those are not interchangeable questions.

Ambient authority

Many financial systems rely on ambient authority.

A service has credentials that allow it to call another service.

For example:

withdrawal-orchestrator
    can call
custody-service

The custody service trusts the caller because:

service_role = withdrawal-orchestrator

This creates broad authority.

Any code executing under that service identity may now potentially request signatures.

The authorization exists because of who the caller is, not because of which specific economic operation it is authorized to perform.

This is ambient authority.

It is convenient.

It is also the foundation of many confused-deputy problems.

Explicit authority

A capability model changes the question.

Instead of:

withdrawal-orchestrator may request signatures

the model becomes:

withdrawal-orchestrator possesses authority
to sign exactly this withdrawal
for at most this amount
to this destination
before this expiration
under this policy

The authority becomes an object.

For example:

EconomicCapability:
    capability_id
    subject
    action
    asset
    amount
    destination
    operation_id
    issued_at
    expires_at
    issuer

The custody service no longer needs to trust the withdrawal orchestrator with general signing authority.

It verifies whether the supplied capability authorizes the exact requested action.

That is a substantial reduction in privilege.

Capabilities represent permission, not identity

A capability can be held by an authenticated service, but the capability itself represents authority.

This distinction is useful.

Suppose Service A receives:

Capability C:
    withdraw 100 USDC
    from account X
    to address Y

Service A may be authenticated as:

service_A

but its ability to execute the withdrawal comes from C.

If Service A calls the custody system with:

withdraw 200 USDC

the request fails even though Service A is perfectly authenticated.

If it asks for:

withdraw 100 USDC
to address Z

the request also fails.

Identity answers who presented the capability.

The capability answers what that identity is allowed to do.

Capability scope

Economic capabilities should be narrowly scoped.

A capability may bind:

action
asset
amount
source
destination
operation
time window
network
counterparty
policy

For example:

action: external_withdrawal
asset: USDC
network: Base
maximum_amount: 100000
source_account: treasury_01
destination: 0xabc...
operation_id: withdrawal_8841
expires_at: 14:05:00

The more irreversible the operation, the narrower the useful scope.

A capability saying:

may transfer funds

is barely better than a role.

A capability saying:

may settle operation 8841 for at most 100,000 USDC
to destination 0xabc on Base before 14:05

contains enough structure to enforce economic intent.

Authority should follow intent

A useful principle is:

capability scope <= business intent scope

If a customer authorized:

transfer 500
to recipient R

no downstream capability should authorize:

transfer up to 1000
to arbitrary recipient

That would increase authority beyond the original intent.

Every derived capability should preserve or reduce the original authority.

Never increase it.

Attenuation

Capability attenuation means deriving a weaker capability from a stronger one.

Suppose Treasury issues:

C0:
    spend up to 1M USDC
    for settlement batch B

The settlement orchestrator may derive:

C1:
    spend up to 250k USDC
    for settlement operation B1

Then a transaction builder derives:

C2:
    spend exactly 247,812 USDC
    to destination D

Authority becomes narrower at every step:

C2 โІ C1 โІ C0

The important invariant is:

Authority(child) subset_of Authority(parent)

A child capability may restrict.

It must never expand.

Attenuation as an order relation

Let:

C1 <= C0

mean:

every action authorized by C1
is also authorized by C0

Then attenuation requires:

child <= parent

This gives us a useful partial order over authority.

For example:

C0:
    asset โˆˆ {USDC, USDT}
    amount <= 1M
    destination โˆˆ approved_destinations

C1:
    asset = USDC
    amount <= 500k
    destination = D1

Then:

C1 <= C0

If instead:

C2:
    amount <= 2M

then:

C2 not<= C0

The derivation must fail.

Authority conservation

Financial systems already enforce conservation of value.

Capability systems need something analogous for authority.

Suppose a capability authorizes spending:

1M

If it can generate two independent children:

C1 = 1M
C2 = 1M

and both can be consumed independently, the system has created 2M of spend authority from 1M.

That is capability inflation.

So attenuation alone is insufficient.

We also need conservation when authority represents consumable capacity.

Splittable capabilities

Suppose:

Parent capacity = 1M

The system may split it into:

Child A = 400k
Child B = 600k

with:

400k + 600k = 1M

A useful invariant is:

sum(active_child_capacity)
+
consumed_parent_capacity
+
remaining_parent_capacity
<=
original_parent_capacity

This turns delegation into a resource-allocation problem.

Delegation

Delegation means transferring some authority to another principal.

For example:

Treasury
    ->
Settlement Orchestrator
        ->
Custody Executor

Treasury may delegate permission to spend from a settlement reserve.

The orchestrator may delegate only the exact amount required for one transaction.

The custody executor receives execution authority without receiving treasury-wide authority.

This is least authority expressed structurally.

Delegation chain

A delegated capability should preserve lineage.

For example:

C0 issued by Treasury
    ->
C1 derived by Settlement Engine
        ->
C2 delegated to Custody

Each capability contains:

parent_capability_id
issuer
delegate
constraints

This creates an authority graph.

It allows the system to answer:

Where did this permission come from?

and:

Which stronger authority allowed it to exist?

Transitive delegation

Delegation becomes dangerous when recipients can delegate again.

Suppose:

Treasury -> Service A

Treasury intends Service A to execute a payment.

But Service A can derive:

Service A -> Service B

Then Service B derives:

Service B -> Service C

Eventually authority reaches code Treasury never intended to trust.

Capability models should therefore include delegation constraints.

For example:

delegation_depth = 0

means:

holder may exercise
holder may not delegate

Or:

delegation_depth <= 2

limits propagation.

Delegation rights are themselves authority

A capability may distinguish:

use
delegate
attenuate
split
revoke

These are different permissions.

Someone allowed to exercise a capability does not automatically need permission to mint child capabilities.

For example:

Custody Executor:
    may_use = true
    may_delegate = false

This reduces authority propagation.

The confused deputy

The confused-deputy problem appears when a privileged service performs an action using its own authority on behalf of a less-privileged caller without correctly binding the action to the caller's permission.

Financial systems are full of potential deputies.

Consider a custody service.

It has broad authority over treasury keys.

A withdrawal service sends:

sign transaction T

If custody checks only:

caller == withdrawal-service

then the withdrawal service can potentially make custody sign any transaction accepted by that interface.

Custody has become a deputy using its own authority.

The correct design requires the withdrawal service to present a capability proving:

transaction T is specifically authorized

Custody should not spend its own ambient authority merely because the caller has the right service identity.

Confused-deputy example

Suppose Service A is allowed to request refunds.

Service B owns treasury execution.

A request arrives:

refund customer 500

Service A sends to B:

transfer 500 to destination X

If B trusts A generally, an attacker compromising A may change X.

A proof-carrying capability might instead bind:

refund_id
amount
asset
destination
original_payment

Service B verifies that the requested transfer exactly matches the authorized refund.

Now A can orchestrate.

It cannot redefine the economic intent.

Capability laundering

Another failure mode occurs when restricted authority passes through a subsystem and emerges as unrestricted authority.

Suppose:

C:
    may transfer 100 USDC
    to destination A

Service X consumes this capability and produces:

authorization_status = approved

Service Y later interprets:

approved == arbitrary transfer allowed

The destination restriction disappeared.

Authority was laundered through a lossy representation.

This is the capability equivalent of collapsing settlement semantics into status=completed.

Semantic preservation across boundaries

Every service boundary should preserve relevant authorization constraints.

If input authority says:

asset = USDC
amount <= 100
destination = A

the next layer cannot reduce it to:

authorized = true

unless that boolean is scoped to a specific immutable operation already containing those constraints.

Otherwise downstream code receives more semantic freedom than upstream policy intended.

Bind authority to operation identity

A strong capability should normally reference:

business_operation_id

For example:

operation_id = withdrawal_8841

Now the capability cannot authorize another withdrawal even if amount, asset, and destination happen to match.

This protects against authority reuse across business intents.

Replay attacks

Suppose a capability authorizes:

withdraw 500 USDC

The operation succeeds.

An attacker submits the same capability again.

If signature verification is the only check, the capability remains perfectly authentic.

The second request may also succeed.

Cryptographic validity does not imply freshness.

Replay prevention must be explicit.

Nonces

A capability may contain a unique nonce:

nonce = 8f12...

The execution boundary records:

nonce consumed

A repeated capability fails.

Conceptually:

if consumed(nonce):
    reject replay
else:
    atomically mark consumed
    execute

The word atomically is doing serious work here.

Check-then-act is unsafe

This is incorrect:

1. query nonce table
2. nonce unused
3. execute withdrawal
4. mark nonce used

Two concurrent requests can both observe:

unused

and both execute.

The consumption must be part of the authoritative state transition.

For example:

BEGIN

INSERT consumed_nonce
    IF NOT EXISTS

reserve funds

create withdrawal

COMMIT

If another transaction tries the same nonce, it fails.

Idempotency and replay are related but different

Idempotency answers:

If the same business request arrives again,
can we return the original result?

Replay protection answers:

Can the same authority create another effect?

Suppose a withdrawal succeeds but the caller times out.

It retries.

The system should not respond:

replay attack

if the retry refers to the same operation.

It should return:

withdrawal already executed

Therefore the capability should bind:

operation_id

and the execution service should preserve the operation result.

Stable economic identity

A useful model:

operation_id:
    identifies economic intent

capability_id:
    identifies authority

attempt_id:
    identifies execution attempt

A retry may create a new attempt.

It should not create a new economic operation.

Nor should it consume the capability twice.

One-shot capabilities

Some authority should be exercised exactly once.

For example:

execute withdrawal W

The state machine is:

Issued
    ->
Consumed

with optional:

Issued
    ->
Revoked

Once consumed:

Consumed is terminal

The capability remains historically valid as evidence.

It no longer grants authority.

Metered capabilities

Other capabilities represent divisible capacity.

Example:

may settle up to 1M today

This is not one-shot.

It is metered.

The system must track:

authorized_amount
consumed_amount
remaining_amount

Invariant:

consumed_amount <= authorized_amount

Each consumption must be atomic.

Partial consumption

Suppose:

capability capacity = 1M

One operation consumes:

300k

Remaining:

700k

Another consumes:

500k

Remaining:

200k

A request for:

300k

must fail.

This sounds trivial.

It stops being trivial when consumption is distributed across services.

Central consumption authority

One solution is to maintain a single authoritative capability ledger.

Every consumer reserves capability capacity through that ledger.

For example:

CapabilityLedger:
    authorized: 1M
    reserved: 200k
    consumed: 600k
    remaining: 200k

This prevents double consumption.

The tradeoff is coordination.

Distributed capability spending

If several services must consume the same capability without central coordination, correctness becomes much harder.

Each service may believe capacity remains.

This is essentially double spending of authority.

Financial capability systems should be very cautious about distributing mutable consumable authority without a clear ownership protocol.

One clean solution is to split capability capacity into non-overlapping child capabilities before distribution.

Instead of:

shared capability = 1M

issue:

Service A capability = 400k
Service B capability = 600k

Now consumption domains are isolated.

Capability partitioning

This mirrors financial reserve segmentation.

Shared authority maximizes flexibility.

Partitioned authority improves fault isolation.

If Service A is compromised, the maximum spend is:

400k

not:

1M

Capability allocation therefore becomes part of blast-radius engineering.

Capability amplification

A dangerous derivation bug may accidentally create stronger authority.

Suppose:

Parent:
    amount <= 100

A child derivation function mistakenly interprets missing amount as:

unlimited

Then:

attenuate(parent, child_constraints)

has actually amplified authority.

This is why constraints should not rely on ambiguous omission semantics.

Missing should usually mean:

inherit parent constraint

not:

remove constraint

Deny by construction

A safe attenuation API should make expansion impossible.

For example:

child.amount =
    min(parent.amount, requested_amount)

not:

child.amount =
    requested_amount

Similarly:

child.expiry =
    min(parent.expiry, requested_expiry)

Destination sets should satisfy:

child.destinations subset_of parent.destinations

Asset sets:

child.assets subset_of parent.assets

Formal attenuation property

Let Perm(C) be the set of actions capability C permits.

Then:

Attenuate(C, r) = C'

must satisfy:

Perm(C') subset_of Perm(C)

For all valid attenuation requests r.

This is a useful property for formal verification.

It is much stronger than unit-testing a few examples.

Capability composition

Sometimes an operation requires several independent capabilities.

A treasury transfer may require:

funding capability
+
liquidity capability
+
compliance capability
+
custody capability

The final operation is valid only if every required authority exists.

Conceptually:

Execute(T)
requires
    C_funds
    AND C_liquidity
    AND C_compliance
    AND C_custody

This limits single-service authority.

Composition should intersect authority

When several capabilities combine, the result should generally reflect the intersection of their permissions.

Suppose:

Funds:
    max 1M

Liquidity:
    max 700k

Compliance:
    max 500k

The operation cannot be:

1M

The effective limit is:

500k

because all constraints must hold.

Threshold authorization

Some capabilities represent authority from independent parties.

For example:

3 treasury signers
2 required

or:

Risk approval
Treasury approval
Custody approval

This is different from attenuation.

It is threshold composition.

A high-value operation may require:

k-of-n authorities

before execution.

This reduces single-point compromise.

Threshold is not automatically safe

Suppose three approval services exist.

All three depend on the same administrator account.

Nominally:

3 independent approvals

Operationally:

1 shared compromise domain

Authority independence has the same hidden-correlation problem we saw with liquidity and guarantees.

Security topology matters.

Context binding

A capability should often bind environmental context.

For example:

network = Base
chain_id = 8453
contract = X

Without this, a signature intended for one context may be replayed elsewhere.

This is particularly relevant in blockchain systems.

The economic intent should include enough domain separation to prevent cross-context reuse.

Asset identity

Never bind authority merely to:

symbol = USDC

Symbols are presentation metadata.

A capability should bind to canonical asset identity.

For example:

network
contract_address
asset_namespace

Otherwise a token sharing the same symbol could satisfy the capability superficially.

Economic authorization must bind to the actual asset.

Destination identity

Likewise, destination should be canonicalized.

Possible forms include:

bank_account_id
wallet_address
merchant_id
beneficiary_id

The capability should bind to the destination identifier used by execution.

If policy approved beneficiary B, execution should not reinterpret a free-text alias later.

Amount semantics

Amount should include:

asset
minor-unit scale
rounding rules
fee semantics

Suppose capability authorizes:

100 USDC

Does that include network fee?

Can execution send:

100 + fee

from treasury?

Can fee volatility increase spend beyond authorized amount?

Capabilities need explicit fee policy.

For example:

principal <= 100
fee <= 2
total <= 102

Otherwise fee handling becomes authority expansion.

Time authority

Capabilities often have expiration:

expires_at

But expiration depends on clock semantics.

Which clock?

Execution node clock?

Database clock?

Issuer clock?

Distributed clock skew can create inconsistent decisions.

For high-value authority, expiration validation should use a trusted time source or bounded clock skew.

The system should know the maximum tolerated skew.

Not-before constraints

A capability may also have:

not_before

This prevents premature execution.

Useful for scheduled settlements, withdrawal windows, or delayed releases.

Again:

not_before <= execution_time <= expires_at

must use clearly defined time semantics.

Revocation

Expiration handles planned authority lifetime.

Revocation handles authority that must end early.

Reasons include:

settlement reversed
customer account frozen
destination compromised
policy changed
issuer compromised
operator mistake

A capability model without revocation assumes every issued permission remains safe until expiry.

That assumption gets uncomfortable quickly around money.

Revocation models

One option is online validation.

Every execution asks:

is capability still valid?

This gives fast revocation.

It also creates a dependency on the revocation service.

If it is unavailable, the system must choose fail-open or fail-closed.

For financial authority, fail-open can be an expensive personality trait.

Short-lived capabilities

Another strategy is issuing capabilities with very short lifetimes.

For example:

expires in 30 seconds

Revocation becomes less critical because authority naturally decays quickly.

This works well when capabilities can be regenerated cheaply.

It works poorly for offline or long-running workflows.

Revocation epochs

A subject may carry a revocation epoch.

For example:

account_authority_epoch = 17

The capability contains:

epoch = 17

If the account is frozen:

account_authority_epoch = 18

All older capabilities become invalid.

This revokes an entire class of authority efficiently.

Epoch granularity matters

A global epoch revokes everything.

That may be too broad.

A system may maintain epochs for:

account
asset
action class
provider
policy

For example:

withdrawal_epoch

can revoke withdrawals without invalidating internal transfers.

This is more precise.

Revocation under partition

Suppose a capability was issued.

Then the revocation service becomes unreachable.

A downstream executor cannot know whether the capability was revoked.

This is a partial-observability problem again.

The system needs a policy.

Possible behavior:

high-risk action:
    fail closed

low-risk action:
    allow if capability is very fresh

emergency mode:
    require secondary approval

Revocation semantics should be designed before the network partition, not improvised during it.

Offline capability risk

The more independently a capability can be verified, the harder immediate revocation becomes.

This is a fundamental tradeoff.

Offline verification improves availability.

Online revocation improves control.

There is no magic configuration that maximizes both.

The system must choose based on consequence.

Capability freshness

A capability can be authentic and unrevoked but still based on stale state.

Suppose:

capability:
    withdraw 100k

issued when balance was:

150k

Another operation consumes:

100k

The capability is still authentic.

It is now economically stale.

This is why capabilities should either reserve capacity or bind to state versions.

Reservation-backed capability

A stronger capability is issued only after reserving the underlying economic resource.

For example:

reserve 100k
issue capability referencing reservation

Now another operation cannot consume the same funds.

The capability carries exclusive authority over reserved capacity.

This is much safer than issuing a statement about unreserved balance.

Capability-backed escrow

For larger workflows, authority may map to escrowed value.

For example:

SettlementCapability:
    escrow_account
    reserved_amount
    destination

Execution spends only from escrow.

This isolates authority from changes elsewhere in the account.

The cost is reduced liquidity flexibility.

Again, resilience versus efficiency.

Capability laundering through queues

Messaging systems create another subtle problem.

Suppose Service A validates capability C and enqueues:

execute withdrawal W

Service B later consumes the queue message.

If the queue message contains only:

withdrawal_id

the proof context is lost.

Service B trusts that A must have validated correctly.

That is ambient authority reintroduced through messaging.

The queued command should carry:

capability reference
proof context
authorization decision identity

or reference an immutable authorized operation record.

Authority at rest

Once an authorized operation is persisted, the database row itself may become the capability.

For example:

Withdrawal:
    id
    status = AUTHORIZED

Any worker that can transition it may now execute economic authority.

This is not necessarily wrong.

But authorization state becomes security-critical.

The system must control who can create AUTHORIZED records and under what proof.

Database privilege escalation

Suppose an internal tool allows operators to edit withdrawal state.

An operator changes:

PENDING_REVIEW

to:

AUTHORIZED

The worker sees the row and executes.

The operator has effectively minted a financial capability through database mutation.

This is why economically meaningful state transitions should happen through domain operations, not arbitrary row editing.

Manual authority

Operators legitimately need emergency powers.

Those powers should be explicit.

For example:

ManualOverrideCapability:
    operator
    operation
    action
    amount
    reason
    second_approver
    expires_at

Emergency access is still capability-based authority.

It is simply issued under a different policy.

Break-glass capabilities

A break-glass capability may allow emergency action outside normal policy.

It should have stronger audit requirements:

short lifetime
high visibility
mandatory reason
multi-party approval
automatic post-incident review

The important principle is that emergency authority becomes more observable as it becomes more powerful.

Not less.

Capability graphs

Once delegation exists, authority forms a graph.

For example:

Treasury Root Authority
        |
        v
Settlement Batch Capability
        |
        +------> Payment A
        |
        +------> Payment B
        |
        +------> Payment C

Or:

Customer Intent
    |
    v
Withdrawal Authorization
    |
    v
Custody Signing Capability
    |
    v
Chain Execution Capability

This graph is useful for security analysis.

Authority blast radius

If capability C is compromised, the graph tells us:

which descendant authorities remain usable?

A broad capability near the root has large blast radius.

A narrow leaf capability has small blast radius.

This gives us an architectural metric:

authority blast radius

not merely permission count.

Dominators in authority graphs

Suppose every high-value withdrawal capability descends from one treasury capability.

That capability dominates the authority graph.

Compromising it compromises the whole path.

Graph analysis can identify such concentration.

This is analogous to shared failure domains in economic contagion.

Security authority also has concentration risk.

Capability concentration

A platform may have thousands of microservices but one credential capable of:

sign any treasury transaction

Operational architecture looks distributed.

Authority architecture is centralized.

That is a meaningful security mismatch.

Least authority

The principle of least privilege becomes sharper as least authority.

A service should receive:

only the economic capability required
for the current operation
for the shortest useful period
over the smallest useful amount

This is more concrete than assigning generic roles.

Privilege escalation

Privilege escalation occurs when an actor obtains authority stronger than intended.

In capability systems this may happen through:

bad attenuation
scope confusion
claim substitution
capability replay
delegation bugs
issuer compromise
context confusion

Each path should be threat-modeled explicitly.

Claim substitution

Suppose the system expects a capability proving:

withdrawal_authorized

but accepts any signed claim from the same issuer.

An attacker presents:

internal_transfer_authorized

If claim type is not bound into verification, signature validity may pass.

The wrong semantic claim gets substituted.

Every capability signature must cover the complete canonical object, including action type.

Audience restriction

A capability intended for Custody Service should not necessarily be usable by another service.

Bind:

audience = custody-service

Then another consumer rejects it.

This prevents authority from being replayed across service boundaries.

Purpose restriction

Audience identifies who may consume the capability.

Purpose identifies why.

For example:

purpose = settlement_execution

This prevents a capability issued for settlement from being repurposed for collateral transfer.

Context must be explicit.

Capability wrapping

Sometimes a service needs to transform authority into another representation.

For example:

EconomicCapability
    ->
blockchain transaction signature

The transformation should be one-way in authority.

The signature authorizes one concrete transaction.

It should not allow recovery of general custody authority.

This is a healthy authority collapse.

Signing as terminal attenuation

A fully specified transaction signature can be viewed as an extremely narrow capability:

execute exactly these transaction bytes

Once the transaction is fixed, many degrees of freedom disappear.

This is desirable.

The closer execution gets, the narrower authority should become.

Late binding

Sometimes destination or amount cannot be known early.

Capability design then needs bounded late binding.

For example:

destination in merchant_set
amount <= 100k

Later the orchestrator selects:

destination = merchant_42
amount = 72k

This is safe if selection remains inside the original constraint set.

Late binding should narrow authority, not reopen previously fixed fields.

Capability race conditions

Two services may try to consume the same remaining capacity simultaneously.

Suppose:

remaining = 100k

Service A wants:

70k

Service B wants:

60k

Both individually fit when read.

Together:

130k

does not.

Capability consumption requires serialization or atomic conditional updates.

For example:

UPDATE capabilities
SET consumed = consumed + 70000
WHERE
    id = C
    AND authorized - consumed >= 70000

Only one conflicting transaction can succeed once capacity falls below the requested amount.

Durable consumption

Capability consumption must survive crashes.

Suppose:

capability marked consumed

then the external request fails before submission.

Can it be retried?

The answer depends on state machine design.

A safer flow separates:

Reserved
Executing
Consumed
Released

For example:

Issued
    ->
Reserved
        ->
Consumed

or:

Reserved
    ->
Released

after safe failure.

Unknown execution outcome

The hardest case:

capability reserved
external request sent
timeout

The system does not know whether the economic action occurred.

It must not:

release capability

immediately.

That could permit duplicate execution.

The capability enters:

ExecutionUnknown

until reconciliation establishes the outcome.

Capability state therefore inherits the same unresolved semantics as settlement state.

Capability state machine

A more realistic lifecycle:

Issued
    |
    v
Reserved
    |
    v
Executing
   / \
  /   \
 v     v
Consumed   ExecutionUnknown
               |
          +----+----+
          |         |
          v         v
      Consumed    Released

And separately:

Issued -> Revoked
Reserved -> RevokedBeforeExecution

depending on policy.

Revocation after reservation

If a capability has reserved funds but has not executed, revocation may release the reservation.

But if execution may already have started, revocation cannot simply undo reality.

The system must inspect execution state.

Again:

revocation != rollback

A familiar pattern by now.

Capability ledger

Financial systems may benefit from an explicit capability ledger.

Not a financial ledger.

An authority ledger.

It records:

issued authority
delegated authority
reserved authority
consumed authority
revoked authority
expired authority

This creates an auditable history of who could have done what.

Authority reconciliation

Just as balances are reconciled, capability capacity may need reconciliation.

For a metered capability:

authorized =
    remaining
    + reserved
    + consumed
    + revoked_unused

subject to the capability's semantics.

If totals do not reconcile, authority has disappeared or multiplied.

Neither is a good sign.

Capability observability

Useful metrics include:

active capability value
capability value by issuer
capability value by action
delegation depth
expired but unconsumed authority
revocation lag
execution-unknown capability value
largest authority concentration
break-glass capability usage

These expose security state in economic units.

That is often much more meaningful than counting tokens.

Value-at-authority

Suppose two credentials are compromised.

Credential A can read customer names.

Credential B can issue 50M of withdrawal capability.

Both are security incidents.

Their economic blast radius is obviously different.

Capability architecture allows direct measurement:

value_at_authority

or more precisely:

maximum economic effect currently authorized

This is useful for incident prioritization.

Issuer compromise

Suppose the capability issuer is compromised.

An attacker can create validly signed capabilities.

Verification succeeds.

This means issuer trust must be bounded.

An issuer should have its own issuance limits:

max capability value
allowed actions
allowed assets
allowed destinations
maximum lifetime

The issuer itself should not possess unlimited authority merely because it creates tokens representing authority.

Issuance budget

For example:

Availability Engine:
    may issue <= 5M aggregate withdrawal capability

Treasury Engine:
    may issue <= 50M settlement capability

Issuance capacity can itself be backed by reservations.

Now compromising the issuer does not automatically expose the entire platform.

Root authority

Eventually capabilities originate from some root authority.

Examples:

customer mandate
treasury mandate
contractual authorization
governance decision
custody key policy

The root should be rare and strongly protected.

Most production operations should use attenuated descendants.

The root should not circulate through ordinary services.

Capability roots and institutional authority

A financial capability is ultimately meaningful because some institution recognizes the authority behind it.

Cryptographic signatures enforce technical authenticity.

The economic system gives them meaning.

For example:

Customer signed intent

matters because the platform accepts that customer as holder of the relevant funds.

Treasury approval

matters because corporate policy gives treasury that authority.

Capability security therefore combines cryptographic structure with institutional semantics.

Formal properties

Several properties are worth stating explicitly.

Attenuation:

Perm(child) subset_of Perm(parent)

Conservation:

consumed
+ reserved
+ remaining
<= authorized

Replay safety:

one one-shot capability
cannot create more than one economic effect

Scope safety:

Execute(action, capability)
implies
action in Perm(capability)

Delegation safety:

Delegated(child, parent)
implies
Perm(child) subset_of Perm(parent)

Expiry safety:

now > expires_at
implies
not Executable(capability)

Audience safety:

consumer != audience
implies
not Executable(capability)

State binding:

required_state_version != current_state_version
implies
Revalidate

These are good candidates for model checking or formal verification.

A Rust sketch

A simplified capability type:

#[derive(Debug, Clone)]
pub struct EconomicCapability {
    pub capability_id: String,
    pub parent_id: Option<String>,

    pub holder: String,
    pub audience: String,

    pub action: Action,
    pub asset: AssetId,

    pub max_amount: u128,
    pub consumed_amount: u128,

    pub source_account: String,
    pub destination: DestinationConstraint,

    pub operation_id: Option<String>,

    pub not_before: u64,
    pub expires_at: u64,

    pub delegation_depth_remaining: u8,
    pub nonce: [u8; 32],

    pub issuer: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Action {
    InternalTransfer,
    ExternalWithdrawal,
    Settlement,
    Refund,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AssetId {
    pub namespace: String,
    pub network: String,
    pub identifier: String,
}

#[derive(Debug, Clone)]
pub enum DestinationConstraint {
    Exact(String),
    AllowList(Vec<String>),
}

The representation is not the difficult part.

The semantics are.

Attenuation function

Conceptually:

pub fn attenuate(
    parent: &EconomicCapability,
    requested_amount: u128,
    destination: DestinationConstraint,
    requested_expiry: u64,
) -> Result<EconomicCapability, CapabilityError> {
    if requested_amount > parent.remaining_amount() {
        return Err(CapabilityError::AuthorityExpansion);
    }

    if requested_expiry > parent.expires_at {
        return Err(CapabilityError::AuthorityExpansion);
    }

    if !parent.destination.contains(&destination) {
        return Err(CapabilityError::AuthorityExpansion);
    }

    if parent.delegation_depth_remaining == 0 {
        return Err(CapabilityError::DelegationForbidden);
    }

    // Construct child with strictly narrower authority.
    todo!()
}

The production implementation would need atomic reservation of parent capacity as part of child issuance.

Otherwise two concurrent attenuations can over-allocate the parent.

Safe derivation requires reservation

Suppose:

Parent remaining: 1M

Two concurrent requests derive:

Child A: 700k
Child B: 700k

Both read:

remaining = 1M

Both appear valid.

Together they create:

1.4M

Therefore child creation must consume or reserve parent authority atomically.

Capability derivation is itself an economic state transition.

Authority cannot be treated as metadata

This is the broader lesson.

If capability issuance can increase economic authority, it belongs in the same category as balance mutation.

It requires:

atomicity
idempotency
durability
auditability
reconciliation

Treating capabilities as disposable JWT-like metadata misses the economic consequences.

Capability systems can fail financially while remaining cryptographically correct

This is perhaps the most important security point.

Every signature can verify.

Every nonce can be unique.

Every certificate can be valid.

The system can still be economically wrong because:

capability was too broad
delegation expanded authority
capacity was double allocated
issuer had excessive authority
revocation arrived too late
context was ambiguous

Cryptographic correctness is necessary.

It is not sufficient.

Security boundary

The real security property is not:

token authentic

It is:

the resulting economic action
was inside the exact authority
intentionally granted by the system

That property spans application state, business policy, ledger state, cryptography, and distributed execution.

Capability security and proof-carrying state

The previous model gave us:

Evidence
    ->
Claim

Capability security extends the chain:

Evidence
    ->
Claim
        ->
Capability
            ->
Reservation
                ->
Execution

Each stage narrows the set of possible actions.

That monotonic narrowing is desirable.

As the operation approaches irreversible external execution, ambiguity should decrease.

Authority should shrink toward execution

Early in a workflow:

customer may withdraw up to 10k today

Later:

withdrawal W may transfer 2k

Later:

transaction T may send exactly 2k to address A

Finally:

signed transaction bytes X

The authority becomes progressively narrower.

This is the opposite of many service architectures, where generic upstream approval becomes increasingly ambiguous as it travels through the system.

Security under partial failure

Distributed failure complicates authority.

A capability may be:

reserved locally
executed externally
confirmation lost

The correct state is not:

unused

It is:

execution outcome unknown

The authority remains unavailable until reconciliation determines whether the action occurred.

This prevents retries from double spending authority.

Capability debt

There is also such a thing as outstanding authority.

Suppose the system issues large numbers of long-lived capabilities.

Even if none are currently used, they represent latent economic power.

This can be viewed as capability debt.

A platform may have:

10M active balances

but:

80M currently exercisable capabilities

That second number deserves attention.

Authority exposure can exceed current transaction flow.

Minimize dormant authority

A useful principle:

issue authority as late as practical
expire it as early as practical

Do not pre-issue broad financial capabilities merely because execution might happen later.

Dormant authority is attack surface.

Conclusion

Distributed financial systems do not merely authenticate actors.

They distribute economic authority.

A service may receive permission to withdraw, settle, sign, refund, release collateral, allocate liquidity, or delegate part of that authority to another component.

When this authority is implicit in roles, service identities, database fields, or generic approval booleans, its boundaries become difficult to reason about.

Capability security makes authority explicit.

A capability answers:

who may act
what action is permitted
over which value
for which operation
under which constraints
for how long
and whether that authority may be delegated

From there, several invariants become enforceable.

Authority can be attenuated but not amplified.

Consumable authority can be split but not duplicated.

One-shot authority cannot be replayed.

Delegated authority cannot exceed its parent.

A privileged deputy cannot substitute its own ambient authority for the caller's bounded permission.

Revocation removes future authority without rewriting history.

Unknown execution outcomes retain their reservation until reconciliation resolves them.

The deeper principle is that authority behaves like a scarce resource.

It can be issued.

It can be delegated.

It can be partitioned.

It can be consumed.

It can be revoked.

And, if the architecture is careless, it can be accidentally multiplied.

That gives us a useful safety property:

For every economically significant action A,
there must exist an authority chain C such that:

A is inside the scope of C,

every delegation step preserves or reduces authority,

the relevant capacity has not already been consumed,

and execution cannot produce more economic effect
than the original authority intended.

Financial systems already work hard to prevent double spending of value.

They should apply the same seriousness to double spending of authority.

๐Ÿ“ฐ 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.