Skip to content

Security Model

LedgerFlow's security model is built on cryptographic bindings, typed constraints, and time-bounded authority. Every authorization decision is deterministic, verifiable without network calls, and produces a tamper-proof audit trail.

Core Security Properties

Property Mechanism
Scoped Typed constraints limit authority to specific merchants, tools, amounts
Temporal Warrants expire; proof freshness enforced via timestamp + nonce
Bound Proof is cryptographically bound to the exact x402 quote and HTTP request
Delegatable Monotonic attenuation ensures delegation only narrows authority
Replay-proof Atomic nonce storage with TTL prevents replay attacks

Replay Protection

Replay protection combines freshness with idempotency.

Freshness

  • created_at_ms must fall within a 60-second verification window
  • Outside the window → reject as stale or pre-dated

Nonce-Based Replay Detection

The merchant verifier stores challenge_id + nonce with an atomic insert:

SET challenge_id:nonce 1 PX 300000 NX

If the key already exists → reject as replay.

Idempotent Retries

If the same x402 request is retried with the same payment identifier:

  • Return the cached prior result (success or failure)
  • Do not re-verify or re-settle

If the same nonce appears with a different request_hash or accepted_hash:

  • Reject immediately as replay

Signature Verification

Warrant Signature

The warrant signature covers the canonical signed bytes of the warrant envelope:

ED25519_VERIFY(
    issuer.public_key,
    SHA256(canonical_warrant_bytes),
    warrant.signature
)

Proof Signature

The proof signature covers the proof preimage:

ED25519_VERIFY(
    subject_signer.public_key,
    SHA256(CBOR(proof_preimage)),
    proof.signature
)

Both must pass. Failure of either rejects the authorization.

Threat Model

Protected Threats

Threat Defense
Prompt injection → unauthorized payment Typed constraints limit scope even if agent is compromised
Credential theft Warrants are not credentials; stealing a warrant only grants bounded authority
Replay attack Nonce-based detection with atomic TTL storage
Expired warrant usage Temporal validity window enforced at verification
Unauthorized delegation Monotonic attenuation + max_depth enforcement
Cross-merchant warrant reuse Audience scope constraint

Out of Scope

Threat Reason
Compromised issuer key If the issuer key is compromised, all issued warrants are suspect. Key rotation and revocation are planned for v2.
Side-channel attacks Cryptographic implementation is outside the protocol scope
Network-level attacks TLS and transport security are assumed
LLM hallucination LedgerFlow constrains what an agent can do, not what it should do

Revocation

LedgerFlow v1 uses a simple revocation model:

  • Short-lived warrants — default expiry in minutes reduces the revocation window
  • Warrant ID denylist — issuers can publish a list of revoked warrant IDs
  • Merchant-side cache — merchants can check revoked warrant IDs locally

Future: Consistency Tokens

v2 may introduce freshness tokens inspired by Zanzibar Zookies or SpiceDB ZedTokens:

  • Issuer publishes a revocation snapshot with a consistency token
  • Verifiers include the token in their authorization decision
  • Guarantees freshness across distributed state

This is explicitly a v2 extension, not a v1 requirement.

Key Management

Signer Key Rotation

  • Rotate signing keys periodically
  • Old warrants remain valid until expiry (short TTL)
  • No revocation needed for natural expiry

Issuer Key Security

  • Issuer keys should be stored in secure enclaves or HSMs
  • Never embed issuer keys in agent code
  • Use separate keys for different delegation levels

Implementation Pitfalls

DO

  • Use deterministic CBOR for canonical encoding
  • Verify proof binding to both accepted_hash and request_hash
  • Use atomic nonce insertion (never check-then-set)
  • Keep verification CPU-only (no network calls)
  • Fail closed on any verification error

DO NOT

  • Cache by signer alone (use warrant_digest)
  • Accept warrants with expires_at beyond 90 days
  • Skip replay protection for "trusted" agents
  • Allow constraint expansion during delegation
  • Use non-canonical serialization for digest computation

See Also