Skip to content

Security architecture

  1. Assume the database leaks. The operational database must be worthless to an attacker: no images, no document numbers, no biometric templates — only statuses, hashes, and wrapped keys.
  2. The device is untrusted. Anything a phone or browser holds must be incapable of reading personal data or touching other users.
  3. Uncertainty fails safe. Any component being unavailable or unsure degrades to manual review, never to approval.
  4. History is evidence. Every material action is append-only and hash-chained.

Every artifact (ID photo, selfie frame, extraction JSON) is encrypted the moment it arrives:

artifact ──AES-256-GCM──> blob on disk/object storage
key (random, per artifact)
└──wrapped by──> master key (env / KMS / hardware-guarded)
└── only the *wrapped* key is stored in the DB
  • AAD binds each blob to its verification ID — a blob can’t be replayed under another record.
  • The master key never touches the database or the vault storage.
  • Erasure = destroying the wrapped key. The blob — every copy of it, including offline archives — becomes noise. This is what makes retroactive deletion honest.
API keyHandoff token
Held byYour backendUser’s device
LifetimeUntil rotated30 minutes
ScopeWhole APIOne verification’s capture flow + bare status
StorageCompared constant-time; logged as SHA-256 fingerprint onlyDB-backed → individually revocable
Worst case if stolenRotate the key (comma-separated list supports zero-downtime rotation)Attacker can upload images to one pending verification for a few minutes — and cannot read anything

Each event stores hash = SHA256(actor, action, verification, detail, timestamp, prev_hash). Verifying the chain end-to-end proves no event was inserted, altered, or removed. Reviewer decisions include their justification note; attestation issuance includes the claim list; erasure is itself an audited event (the fact of deletion is never deleted).

  • TLS everywhere (platform-terminated on the reference deployment).
  • Per-IP sliding-window rate limits, strictest on the unauthenticated-adjacent capture endpoints.
  • Uploads validated for content type and size before touching the pipeline.
  • Webhooks signed (HMAC + timestamp); payloads carry no PII.

Face detection, embedding, pose estimation, and matching run in-process on the server (InsightFace/ArcFace on CPU). No selfie frame, embedding, or template is ever sent to a third-party API — including the AI provider used for document text inspection. Embeddings are computed transiently and not persisted.

Honesty is a security feature:

  • Liveness: the random pose challenge defeats photos, masks-on-sticks, and generic replays, but a targeted attacker with a pre-recorded video of the actual victim performing head turns could get lucky with the sequence. Mitigation: unconfirmed liveness never auto-approves, and a passive anti-spoof model is on the hardening roadmap.
  • Single-operator keys: the reference deployment keeps the master key in platform env vars. For higher assurance, move it to a KMS or hardware token — the code path already supports supplying it externally.
  • Rate limiting is per-instance memory — front it with a CDN/WAF for distributed abuse, or move the limiter to Redis when scaling out.