Security
How Human Sender codes work, what we store, and where.
How codes are generated
Every Verify code is a one-time token generated server-side and bound to the sender's verified account. Minting a code requires a biometric confirmation (Face ID or fingerprint) on the user's registered mobile device. This means no code can be generated via API alone, in bulk, or without a live human physically present.
There are two types of codes:
- ✓Message codes — generated when signing an email, SMS, or message. Valid for 30 days. Can optionally be bound to the exact content of the message via a SHA-256 hash stored at the moment of signing.
- ✓Live call codes — 4-digit rotating codes valid for 2 minutes. Designed for live phone or video calls to prove the person on the call is who they claim to be, right now.
Content binding
When a message code is created with content binding enabled (the default for email), the message body is hashed with SHA-256 and stored alongside the code. The verification page shows: "Joel signed this exact message to you on 14 May 2026 at 09:32."
If the message is altered after signing — by a man-in-the-middle attack, a forwarded thread edit, or any other modification — the hash on the verification page will not match the presented message, and a clear warning is shown to the recipient. This is the strongest anti-tampering guarantee Verify provides.
Anti-abuse mechanisms
- ✓Biometric gate: Every code minting requires Face ID or fingerprint. Bots and scripts cannot pass this.
- ✓Rate limits: Free accounts are limited to 50 codes per day. Higher tiers have higher limits but are still rate-capped.
- ✓Badge revocation: Accounts found to be misusing the platform can have their badge revoked. All existing codes from that account are immediately invalidated.
- ✓Recipient binding: Codes can be bound to a specific recipient email address. If anyone else tries to verify using that code, the verification page flags the mismatch.
- ✓Escalation guard: Verification levels can only be increased by the system after a completed verification step. No user can promote their own trust level via the API.
What we store — and what we do not
We store
- Email address
- Phone number (encrypted)
- Display name and username
- Profile photo (optional, stored in EU)
- SHA-256 hash of signed message bodies
- Code metadata (timestamps, expiry, recipient hint)
- Verification level and audit trail
We do not store
- The plaintext message body
- Biometric data (processed by Didit.me, not retained)
- Private keys (Level 4: stored in device secure enclave only)
- Payment details (handled by Stripe)
- Any data outside the EU
EU data residency
All Human Sender data is stored and processed in the European Union. Our infrastructure sub-processors are:
| Sub-processor | Purpose | Region |
|---|---|---|
| Supabase | Database and storage | EU (Frankfurt) |
| Vercel | Application hosting | EU (Frankfurt) |
| Didit.me | Identity and liveness verification | EU |
Verification levels
Human Sender uses a five-level assurance ladder based on eIDAS and NIST 800-63 standards. Each higher level requires all previous levels.
Badge: None · Email address confirmed.
Badge: Grey checkmark · Live human face confirmed via passive liveness check (micro-movements, skin-tone pulse).
Badge: Blue checkmark · Government-issued ID uploaded and matched to the live face.
Badge: Blue checkmark + employer logo · Employer confirms the user's role via SSO or admin invitation.
Badge: Gold checkmark · Private key stored in device secure enclave; codes signed on-device.
For full details on data processing see our Privacy Policy and Terms of Service. Security concerns can be reported to legal@humansender.com.