Security architecture
Design principles
Section titled “Design principles”- 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.
- The device is untrusted. Anything a phone or browser holds must be incapable of reading personal data or touching other users.
- Uncertainty fails safe. Any component being unavailable or unsure degrades to manual review, never to approval.
- History is evidence. Every material action is append-only and hash-chained.
Envelope encryption
Section titled “Envelope encryption”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.
Credential model
Section titled “Credential model”| API key | Handoff token | |
|---|---|---|
| Held by | Your backend | User’s device |
| Lifetime | Until rotated | 30 minutes |
| Scope | Whole API | One verification’s capture flow + bare status |
| Storage | Compared constant-time; logged as SHA-256 fingerprint only | DB-backed → individually revocable |
| Worst case if stolen | Rotate 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 |
Hash-chained audit log
Section titled “Hash-chained audit log”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).
Transport & perimeter
Section titled “Transport & perimeter”- 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.
Biometric locality
Section titled “Biometric locality”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.
Known limitations (read this)
Section titled “Known limitations (read this)”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.