Security
Threat model, cryptographic primitives, and production hardening checklist.
Threat Model
| Threat | Mitigation |
|---|---|
| Brute-force PIN | Argon2id hashing (slow by design) |
| Replay attacks | Redis idempotency keys (1-hour TTL) |
| Webhook forgery | Constant-time secret comparison |
| IP spoofing | X-Forwarded-For only honored from trusted proxies |
| Double-credit | Atomic order state transitions |
| Key compromise | AES-256-GCM encryption at rest |
| Timing attacks | subtle crate for all secret comparisons |
Cryptography
Wallet Key Derivation
HKDF-SHA256 from master seed + phone number → deterministic ed25519 keypair
Encryption at Rest
AES-256-GCM with 12-byte random nonce per record. Key from WALLET_ENCRYPTION_KEY env var.
PIN Hashing
Argon2id — memory-hard, resistant to GPU and ASIC attacks. 4-digit PINs only.
Secret Comparisons
All authentication checks use the subtle crate for constant-time comparison.
Production Checklist
Before deploying to mainnet:
- ☐ENVIRONMENT=production
- ☐WEBHOOK_SECRET — strong random value
- ☐INTERNAL_API_KEY — strong random value
- ☐WALLET_MASTER_SEED — backed up offline, encrypted
- ☐WALLET_ENCRYPTION_KEY — backed up separately from master seed
- ☐FEE_PAYER_SECRET — funded mainnet account
- ☐DATABASE_SSL=true
- ☐TLS at reverse proxy (Caddy / nginx / ALB)
- ☐TRUSTED_PROXY_IPS set to proxy IP only
- ☐AT_ALLOWED_IPS set to Africa's Talking production IPs
- ☐STELLAR_HORIZON_URL → mainnet Horizon
- ☐STELLAR_NETWORK_PASSPHRASE → mainnet passphrase
- ☐USDC_ISSUER → mainnet Circle USDC issuer
- ☐Security audit of wallet derivation and transaction signing
- ☐Monitoring on failed transactions and refund failures