Security
Last updated: September 2026
We treat the addresses, transaction graphs, and account information you trust to ChainHint as sensitive — even when individual blocks of data are publicly available on-chain. This page describes the controls in place, written plainly. We are a small operator and prefer concrete commitments over marketing badges. For our list of authorised sub-processors see /trust; for the contractual side see /privacy. To receive our standard Data Processing Addendum (GDPR Art. 28 template), contact us with subject "DPA request" — we countersign and return by email within two business days.
1. Data in transit and at rest
- TLS 1.2+ on all public endpoints (chainhint.com, *.supabase.co Edge Functions). HTTP requests are 301-redirected to HTTPS.
- AES-256 encryption at rest for the Postgres database, file storage, and backups (Supabase-managed via AWS).
- API keys and provider secrets are stored in Supabase Vault only — never committed to source control, never exposed to the frontend bundle.
2. Access control
- Row-Level Security (RLS) enforced on every table that holds user data. Anonymous traffic can read only the public reference dataset (entity labels, address risk metadata); private data (incidents, monitored addresses, API keys, payment records) is gated to the owning user's JWT.
- Three-tier role separation: anonymous, authenticated, and service-role. Edge Functions use the service-role key only when explicitly required and never in client-side code.
- API keys for the B2B endpoint are stored as SHA-256 hashes — the plaintext is shown to you exactly once at creation.
- MFA enforced on the operator account used for production access.
3. Audit logging
All cross-tenant administrative actions (operator viewing or modifying another user's incidents, regenerating an AI report on someone else's behalf, triggering manual fund-traces) are written to an append-only admin_audit_log table. The log is captured both at the database layer (via trigger) and at the application layer (via Edge Function helper) so service-role bypasses cannot evade it. Rows are immutable at the application layer — there is no UPDATE or DELETE policy and the frontend cannot write to the table at all. Service-role writes bypass RLS by design, so a compromised service-role key would be able to tamper with history; we mitigate this by rotating the key on any suspected exposure and by keeping Supabase daily backups for forensic recovery.
4. Webhooks and payment flow
- NOWPayments callbacks are verified with HMAC-SHA512 signatures before any subscription state change.
- Quota enforcement uses atomic Postgres locks (
SELECT ... FOR UPDATE) to prevent race conditions where parallel requests could exceed the plan limit. - We never see or store payment card data — NOWPayments handles the on-chain settlement and we receive only invoice metadata.
5. Sanctions screening
Every address lookup is checked server-side against the sanctioned wallet addresses we hold — designations that name the address, by US OFAC and the other authorities that publish them (EU measures among them, as republished by France's asset-freeze register); the UN and UK lists publish no wallet addresses and are screened by name instead. The data is refreshed from the U.S. Treasury's OFAC SDN list (public domain), from France's national asset-freeze register (DG Trésor — Registre national des gels, Licence Ouverte v2.0), which republishes EU and UN restrictive measures, and — for Israel NBCTF seizure orders, FBI Lazarus attributions and some other government lists — from OpenSanctions (CC BY-NC 4.0). When Chainalysis is enabled, we additionally cross-check the queried on-chain address against their public sanctions API for defense-in-depth — only the address is sent, never any user identity, email, IP, or investigation context. Chainalysis is listed as a Tier 2 sub-processor on our Trust page.
6. Backups and disaster recovery
- Daily automated database backups (physical, Supabase-managed), retained for 7 days. Point-in-time recovery is not enabled, so a restore returns the database to the last daily backup.
- RPO ≤ 24 hours, RTO ≤ 8 hours for routine restoration. Source code, migrations, and Edge Function code live in a private GitHub repository and on operator workstations.
- Annual restore drill: we verify that the production schema (tables, RLS policies, indexes, functions) is fully restorable from the Supabase daily backup. The first drill (April 2026) validated schema and policy restorability at the
pg_dump --schema-onlylevel and PASSED with caveats. A full data-level restore to a parallel Supabase project is budget-gated ($16/mo for the parallel project) and planned when revenue supports it; meanwhile, our local PostgreSQL mirror of the publicaddressesandentitiesdatasets serves as a data-level redundancy check. Procedure and evidence reports are public in our docs folder.
7. Monitoring
- Sentry captures errors and performance regressions on both the frontend and Edge Functions, with PII scrubbing rules applied.
- Health-check endpoint at
/functions/v1/health-checkreports database, environment, and stat-cache status. - Per-API quota tracking in
api_usage_logexposes anomalies (spikes, throttle events) so we can react before they become user-visible.
8. Incident response
We maintain a written incident-response runbook covering severity classification (SEV-1/2/3), rollback procedures for Edge Functions and migrations, evidence-preservation steps for suspected breaches, and the GDPR Article 33 notification path. We commit to notifying affected customers within 72 hours of confirming a personal-data breach.
9. Software supply chain
- All code changes go through pull-request review (operator approves their own PRs solo today, but the workflow is in place for additional reviewers).
- The full suite is 6,870 automated tests — 3,173 frontend and 3,697 backend, counted on the run of 10 October 2026 (
ad4867e1). GitHub Actions runs it on every pull request and every push to main — except a merge whose code is byte-for-byte what already passed in its pull request, which it does not run twice, and a push that changes only a deploy record (no code) — and it runs locally before a push as well. - Every pull request and every push to main is also scanned for committed secrets (gitleaks, pinned and checksum-verified, same ruleset as the local pre-commit hook).
- Dependencies are audited against the GitHub Advisory Database; known critical/high vulnerabilities are patched promptly. Residual moderate/low issues are tracked publicly in our changelog.
- Migrations are append-only — schema changes cannot silently destroy data.
10. What we do not yet have
Honest list, in case it matters to you:
- SOC 2 Type II — we have not pursued certification. The controls above mirror the Trust Services Criteria, but no third-party auditor has tested them.
- Third-party penetration test — not yet commissioned. We rely on the test suite and the public security.txt disclosure path below.
- SSO / SAML — not implemented. We support email + Google + GitHub OAuth sign-in.
- Data residency choice — the production database runs in AWS eu-west-1 (Ireland) and there is no option to choose another region; some sub-processors listed on the Trust page process data in the US.
If any of these are blockers for your use-case, contact us directly — we are upfront about the gap and can sometimes work around it.
11. Reporting a vulnerability
If you have found a security issue in ChainHint, please report it via the contact form with subject "Security". Our machine-readable disclosure policy lives at /.well-known/security.txt per RFC 9116. We will acknowledge receipt within 72 hours and keep you updated through the fix.
We do not run a paid bug-bounty program at this stage, but we will publicly credit researchers (with permission) and treat good-faith reports with the seriousness they deserve.