Aller au contenu

Guide

Sécurité

Ce contre quoi nous nous défendons, comment les clés sont conservées aujourd'hui et les promesses que nous ne faisons volontairement pas.

Cette page est disponible en anglais pour le moment.

The model

  • Bounded. The allowance certificate fixes a cap (funded plus credit), a per-payment limit, a maximum number of payments and an expiry. Country packs and KYC tiers keep those numbers low.
  • Detected. Every payment carries a sequence number, a running total and the hash of the previous payment. Two payments that claim the same place in the chain are a fork, and settlement flags it.
  • Recovered. A detected fraud revokes the allowance, opens a fraud case and emits fraud.detected. Any shortfall is taken from the holder's wallet before the risk pool.

Threat model

Threats and mitigations
ThreatMitigation
Same allowance spent twice at different merchantsLow caps; fork detection at settlement; revocation; recovery from the holder, then the risk pool
Replay to the same merchantOne-time request nonce, and the merchant rejects payments it already holds
Replay to a different merchantEvery payment is signed over the merchant ID
Counter rollback on the deviceThe hash chain turns a rollback into a fork
Payment forged by a merchantNeeds the payer's device private key
Forged allowanceNeeds the partner's issuer private key; merchants check it against cached issuer keys
Stolen unlocked phonePIN before signing; limited remaining allowance; the allowance can be revoked
Revoked or expired allowanceChecked offline against the last synced list and the certificate's expiry. Risk inside the sync window is accepted and bounded
Device clock set wrongDevice clocks are not trusted; merchants allow 5 minutes of skew, and payments are ordered by sequence number, not time

What a merchant checks offline

verifyBundle runs on the merchant's device with no network. It rejects a payment if any of these fail:

  • The issuer key is known and the allowance signature is valid.
  • The allowance is inside its validity window and not on the cached revocation list.
  • The payer's signature is valid for the device key named in the allowance.
  • The payment names this merchant and answers this request (nonce, amount, currency).
  • The amount is within the per-payment limit, the running total within the cap, and the count within the maximum.
  • The payment links correctly to the ones this merchant already holds from the same allowance, with no fork.

A merchant only sees its own payments. A double-spend across two merchants passes both offline checks and is caught at settlement. That is the bounded risk.

How keys are held

Key storage in the reference implementation
KeyWhere it lives today
Payer device key (ECDSA P-256)Generated in the browser as a non-extractable WebCrypto key and stored in IndexedDB. It can sign but cannot be exported
App PINNever stored. PBKDF2-SHA-256 with 150,000 iterations and a random salt. Five wrong tries lock signing for five minutes
Partner issuer keys (ECDSA P-256)On the server, encrypted at rest with AES-256-GCM under PV_MASTER_KEY
Partner API keysShown once as pv_<prefix>_<secret>. Only a SHA-256 hash of the secret is stored, compared in constant time
Webhook secretUsed to sign each delivery with HMAC-SHA-256

See Webhooks for how to verify signatures.

Known limits of the reference implementation

The reference wallet is a web app. That is useful for pilots and has limits a native SDK will remove:

  • A browser does not guarantee that a non-extractable key is backed by secure hardware, and it offers no device attestation. Code running in the wallet's origin can ask the key to sign.
  • The PIN gates the wallet's signing flow. It is not bound into the key itself.
  • The offline queue in IndexedDB is not encrypted beyond what the operating system provides.
  • Issuer keys are sealed with a single master key. Production deployments should move them to a KMS or HSM.
  • Development shortcuts (email sign-in without Supabase, a fixed master key) are refused when NODE_ENV is production.
  • No independent security audit has been completed yet.