section 01
Overview
BioFRQ's security posture is built on defence in depth — a chain of independent controls at the network, infrastructure, application, data, and people layers. No single layer is asked to carry the whole load; a failure in one is contained by the next.
This page is the public summary. Customers under NDA can request: our latest internal pentest report, our SOC 2 Type II report (audit in progress, expected H2 2026), our completed CAIQ questionnaire, and a deeper architecture brief. Email security@biofrq.com and we respond within 5 business days.
section 02
Infrastructure
Production runs on dedicated Hetzner servers in Frankfurt, Germany. The Frankfurt location is intentional: an EU jurisdiction with mature data-protection law, located on the European trunk for low-latency reach into all our primary markets.
- Cloudflare sits in front of all public traffic, providing DDoS protection, a managed WAF tuned for the API, and edge TLS termination. The origin firewall rejects any traffic that does not arrive via Cloudflare.
- The API tier, the database, and internal services run on separate network segments. The database is not addressable from the public internet under any condition.
- Operating-system updates are applied within 7 days of release for non-critical patches and within 24 hours for critical CVEs.
- All production servers are configuration-managed; manual changes are detected by automated drift checks and reverted.
section 03
Data isolation
Per-customer isolation is enforced at the database layer, not merely in application code. This is the single most important choice in the architecture: a logic bug in our application code cannot leak data between customers, because the database itself refuses to return rows from another customer's scope.
- Every table that holds tenant data has a PostgreSQL Row-Level Security policy keyed off the current tenant ID set on the session.
- The application connects as a non-owner role (no BYPASS RLS), so the policies fire on every query regardless of which code path issued it.
- Face embeddings are stored in a per-tenant pgvector index; cross-tenant similarity queries are not possible by construction.
- Background jobs that legitimately need cross-tenant scope (e.g., billing aggregation) opt in explicitly via a documented "system mode" that is logged.
- Enterprise customers can opt into a dedicated single-tenant deployment in a separate Hetzner project for additional isolation, including dedicated database, dedicated key material, and a separate Cloudflare zone.
section 04
Encryption
- In transit, external: TLS 1.3 (TLS 1.2 minimum) on all public endpoints — API, dashboard, marketing site, docs. HSTS enabled with a 1-year max-age.
- In transit, edge to origin: encrypted tunnel from Cloudflare to the origin. The origin will refuse any connection that does not present a valid Cloudflare-issued certificate.
- At rest, primary storage: AES-256 full-disk encryption on production servers.
- At rest, backups: off-site daily encrypted backups using a separate KMS-managed key in a separate region (Hetzner Helsinki). Backup encryption keys are rotated annually.
- Application-layer: API key lookup uses an HMAC-SHA256 index keyed by a server-only secret; the key material itself is stored as an Argon2id hash. We cannot read an API key after it is issued — only verify it.
section 05
API credentials
API keys are 256 bits of cryptographic randomness, prefixed with bfq_live_ (production) or bfq_test_ (sandbox) so they are immediately distinguishable in logs and codebases.
- The plaintext key is shown to the user once, at creation. We store an HMAC index (for fast lookup) and an Argon2id hash (for verification). The plaintext is not recoverable.
- Keys can be scoped per environment, per action set, and per rate-limit tier.
- Zero-downtime rotation is supported: create a second key, deploy it, revoke the first. The dashboard surfaces last-used timestamps so stale keys are visible.
- We monitor for leaked keys on public code-hosting services. A confirmed leak triggers automatic revocation and customer notification within 4 hours.
section 06
Authentication and access
Dashboard authentication uses email and password (Argon2id hashed, unique salt) with optional TOTP 2FA. Session tokens are opaque (not JWT), stored server-side, revocable, and expire on a 30-day rolling window with absolute expiry at 90 days.
Internal access controls:
- Principle of least privilege. No employee has standing access to customer biometric vectors. Access is granted per-ticket, tied to a specific support case, time-bounded, and logged.
- Production access. Requires SSH key + hardware security key (FIDO2 / YubiKey). VPN gates access; the VPN itself requires hardware-key MFA.
- Critical operations. Database role-promotion, secrets rotation, customer data exports, and deletions require two-person authorisation captured in the audit log.
- Off-boarding. Departing employees lose access within 1 business day of their last work day; production keys are rotated.
section 07
Logging and audit
Every API request is logged with: request ID, customer ID, action name, HTTP status, latency in milliseconds, billable units, and timestamp. We do not log the request body or response body — no raw images, no embedding vectors, no subject-level inferences.
- Hot retention: 90 days. The dashboard exposes the customer-side view of this log directly so you can audit your own usage in real time.
- Cold retention: 12 months. Used for billing reconciliation, statutory audit, and incident investigation. Access is role-gated and itself logged.
- Operational logs (infrastructure events, internal-service requests, employee actions) are retained 12 months and aggregated in an immutable log store.
section 08
Incident response
A 24/7 on-call rotation owns incident response. Alerts page within minutes of detection. Severity tiers, with our commitments:
- P0 — confirmed data exposure or active intrusion. On-call engagement within 1 hour. Affected customers notified by direct email within 24 hours of confirmation, and in all cases within the 72-hour window required by GDPR Article 33 for qualifying breaches.
- P1 — service down or major degradation. On-call engagement within 1 hour. Status page update within 30 minutes.
- P2 / P3 — partial degradation or single-customer issue. Engagement during business hours unless escalated.
Postmortems are written within 14 days of P0 / P1 resolution and published on status.biofrq.com. We run an incident-response tabletop exercise annually.
section 09
Vulnerability reporting
To report a security vulnerability, contact security@biofrq.com. A PGP key is available on request for sensitive disclosures.
- Acknowledgement within 1 business day.
- Status updates at least weekly until the issue is resolved.
- Coordinated disclosure window: 90 days by default. We will engage in good faith if you need a longer window for a complex issue.
- Public crediton resolved-issue acknowledgements, with the reporter's consent. We currently do not run a paid bug-bounty programme.
- Safe harbour. Good-faith research within the rules of engagement (no DoS, no exfiltration of customer data, no testing against production customer accounts you do not own) will not be reported to law enforcement or pursued in civil action.