Last updated 31 August 2026
Trust & security
What we store, who else touches it, how the system is built, and what we do not yet have. The last part is here because a security review that discovers it later is a worse conversation than one that starts with it.
What we hold, and what we deliberately do not
The single most important fact for a security review: we do not store prompts or model responses. Not as a retention policy — as a property of the schema.
Every request produces one decision record per model attempt. That record is a closed set of typed fields: the concept, classifier confidence and rung, which models were considered, which were eliminated and on what ground, which was chosen, token counts, computed cost, latency and outcome. There is no field that can hold content, and adding one is a schema change argued for in public in our product graph.
| Data | Retention | Notes |
|---|---|---|
| Account email, password hash | Life of account + 30 days | Argon2id; not reversible |
| API keys | Life of account + 30 days | Hash + masked prefix only. The key itself is shown once and is not recoverable by us |
| Provider keys you supply | Until you remove them | Encrypted at rest, key held outside the database. Readable by the running service by necessity — see below |
| Decision records | 13 months | Routing metadata only. No prompt or response content |
| Ledger & payment records | 7 years | Accounting records; statutory |
| Sessions | Until expiry or sign-out | Server-side row, revocable. Token stored hashed |
| Page counts | 26 months | Aggregate only — the table has no column for a person |
| Mailing list | While subscribed; suppression list indefinitely | Consent timestamp retained as proof |
| Prompts & responses | Not stored | Passed to the selected provider and not retained by us |
Sub-processors
The complete list. Adding one is a change to this page and to the privacy policy.
| Provider | Purpose | Data | Location |
|---|---|---|---|
| Hetzner Online GmbH | Hosting | All application data at rest | Germany (EU) |
| Anthropic PBC | Model inference | Prompt content for requests routed to a vendor model | United States |
| Stripe, Inc. | Payments | Payment details, entered on Stripe's own pages | United States / Ireland |
| Postmark (ActiveCampaign) | Transactional email | Email address, message content of the mail itself | United States |
| GitHub, Inc. | Source, CI, container registry | No customer data | United States |
Model providers are the only sub-processors that ever see prompt content, and which providers may receive which traffic is a routing constraint rather than a policy statement — see below.
Residency is enforced, not promised
Most data residency is handled by procurement: choose vendors whose terms say the right things, and audit annually. Nothing in the running software knows about it.
Here, residency is a property of each model and a gate the router runs
before any preference is considered. A request marked
critical is routed only to models whose
weights run inside our infrastructure, and if none is available it is
refused rather than downgraded to a vendor model.
To be exact about what that means today: it is opt-in per request, and no in-infrastructure backend is currently running — so a critical request is refused rather than served. That is the mechanism working, not a gap in it, and it is the honest state of things rather than a claim we would rather make. No concept pins residency by default; a caller who needs the boundary asks for it and gets either it or a straight refusal. You can see the decision for any request without it being served:
curl -X POST https://api.fiferouter.com/v1/explain \
-H 'content-type: application/json' \
-d '{"text":"can this retry double-charge the customer?","critical":true}'
The response names which models were eliminated and why. That endpoint is public, costs nothing, and is the same code path that serves real requests up to the point a provider would be called.
All of it is public
Everything on this page describes code you can read. The router, the control plane that holds accounts and money, the deployment manifests and the CI that gates them are at github.com/Tech-Res-Group/fiferouter, under the GNU AGPL v3. A commercial licence exists for anyone who cannot take those terms.
The control plane is published deliberately, and it is the half that matters here. Claims about residency and about what is not logged live in the code that holds the credentials and the ledger — so publishing only the router would have published the half nobody needed to audit.
| Claim on this page | Where to check it |
|---|---|
| No field can hold prompt or response content | src/fiferouter/decisionlog.py — the record is a frozen dataclass, and tests/router/test_decision_log.py asserts the field list |
| Residency gates before any preference | src/fiferouter/select/selector.py — ranking is handed the survivor set, never the pool |
| API keys are not recoverable | site/api/keys.py — only a hash and a masked prefix are stored |
| Secrets never live in the repository | .github/workflows/security-gate.yml — a blocking scan on every merge |
| Every decision is logged, fallbacks included | src/fiferouter/router.py — one record per model attempt, on every exit path |
The running service makes the same offer:
GET https://api.fiferouter.com/ names its licence
and the source of the build answering you.
Security practices
- Credentials we issue are never recoverable. API keys, session tokens and email-confirmation links are stored as hashes. Passwords use Argon2id. There is no support path that reveals one; the answer to a lost key is to revoke it and issue another.
- A provider key you give us is a deliberate exception, and here is exactly what it means. If you bring your own model-provider credential, we have to present it to that provider, so it cannot be a hash — we have to be able to read it. It is encrypted with AES-256-GCM under a key held in the server's environment and never in the database, and bound to your account and that provider so a row cannot be moved between accounts. What that buys is precise: a database dump is not enough. What it does not buy: anyone who can run code as this service can read it. We will not claim otherwise.
- Secrets never live in the repository. They are held as CI secrets and reach the server through a single deploy key pinned by a forced command to one script, which accepts an allowlist of settings and refuses everything else. That key cannot open a shell.
- Every merge is gated. Secret detection blocks on any finding; dependency and infrastructure scanning block on fixable high-severity issues; static analysis blocks on newly introduced findings. A separate report-only pipeline runs broader scanning, an SBOM and a DAST baseline.
- Containers run unprivileged with an immutable root filesystem, no privilege escalation and all capabilities dropped.
- The router is not internet-reachable. Every request arrives through the edge, having passed TLS termination, header stripping and rate limiting.
- Transport is TLS 1.2+ with certificates issued and renewed automatically.
- Monitoring probes the public endpoints every 15 minutes — including an assertion that the residency constraint still binds — and a twice-daily digest reports routing failures, refusals and billing anomalies.
Data subject requests
Access, correction, deletion, restriction, objection and portability requests go to privacy@fiferouter.com and are answered within 30 days. Account deletion removes account, key and session records within 30 days; ledger entries are retained for the statutory period because they are accounting records.
Reporting a vulnerability
security@fiferouter.com. We will acknowledge within 2 working days and keep you informed until it is resolved. We will not pursue legal action against good-faith research that avoids privacy violations, service degradation and data destruction. There is no bug bounty.
What we do not have
Stated plainly, because a security review that discovers these later is a worse conversation than one that starts with them.
- No SOC 2 or ISO 27001. Neither audit has been undertaken. If your procurement process requires one, we do not currently pass it.
- No contractual uptime guarantee. We publish our monitoring and will be straightforward about outages, but there is no SLA with credits attached.
- No penetration test report. Automated scanning runs on every merge; no third party has tested the running system.
- Single region, single operator. One provider, in Germany, run by one person. There is no multi-region failover and no on-call rotation.
The honest mitigation, since it is the first thing anyone asks: the source is public and you are licensed to run it. Every line of the router, the control plane and the tests is at github.com/Tech-Res-Group/fiferouter under AGPL-3.0. If this operator disappears, you can stand the service up yourself, keep your own routing rules, and read exactly how the residency filter works rather than take our word for it. That is not a promise about our reliability — it is a promise that our reliability need not be your single point of failure. Most vendors at any size cannot offer it, because their product is closed. - No customer-managed encryption keys and no BYO cloud deployment.
If any of these is a blocker, say so before evaluating further — it will save us both the exercise, and we would rather hear which one than discover it at the end.
Data processing agreement
A DPA covering the above is available on request from privacy@fiferouter.com, and we will sign a reasonable customer paper equivalent. Standard Contractual Clauses apply to transfers to sub-processors outside the UK/EEA.