This page describes the security architecture of the in-product fjordFIRE application, the authenticated product. The marketing site you are reading is a separate static surface and does not store user data. The two are deployed independently.
It is the technical companion to the trust page: same posture, with the actual mechanisms (algorithms, providers, processes) named. Meant to be skimmed first and audited second.
Authentication
- Passwordless by design. Sign in with a one-time magic code sent to your email, or with Google OAuth. There is no fjordFIRE password stored anywhere, so a credential leaked from some other service cannot open your account, and there is no password database to breach. It does not make sign-in unphishable: a one-time code can still be talked out of someone in the moment, which is what the TOTP option below defends against.
- Multi-factor available to every household member. Any user in a household can enable TOTP (RFC 6238) via an authenticator app, with printed recovery codes for account recovery. It isn't an admin-only option. SMS-based codes are not offered: SIM-swap is a real attack vector.
- Sessions use secure HTTP-only cookies with
SameSite=Lax(the policy that supports OAuth sign-in callbacks). State-changing routes apply CSRF protection at the API boundary. You can revoke every active session from settings, and a change to your role invalidates existing tokens immediately.
Encryption
- At rest: the database and backups are encrypted by the hosting provider. Sensitive secrets, like TOTP keys and equivalent material, receive additional application-layer encryption with AES-256-GCM.
- In transit: HSTS with preload, sent on every authenticated response. TLS termination is handled by Railway's managed edge.
- Content security: a strict Content-Security-Policy is served on every authenticated page; inline scripts use per-request nonces.
Browser hardening
The app sets a defence-in-depth set of HTTP response headers on every request:
- X-Frame-Options: DENY. The app cannot be embedded in an iframe by another origin. Blocks clickjacking.
- X-Content-Type-Options: nosniff. The browser will not second-guess a declared content type. Blocks MIME-confusion attacks.
- Referrer-Policy: strict-origin-when-cross-origin. Full URLs go to same-origin requests only; cross-origin requests get the origin alone. Limits what third parties learn from a click.
- Permissions-Policy. Camera, microphone, and geolocation are disabled outright.
Audit log
Changes made through fjordFIRE are recorded in an audit log: what changed, who changed it, when, and what the previous value was. You can read the whole thing from inside the app and export it as CSV or JSON whenever you want. It exists so a household can answer “who moved this, and what was it before?” without asking anyone to remember.
Audit rows are kept for the lifetime of the household, and after 180 days the IP address and user-agent recorded against them are deleted. The rest of the entry stays, because the entry is the point.
“Lifetime of the household” means exactly that, and not longer. An erasure request removes the household and its audit log together; there is no residual copy of the log that outlives the account it belongs to.
Hosting
- Region: application servers, database, and backups all run in the EU (Railway, EU region). Two supporting services are operated by US companies and receive a limited slice of data: Google (only if you choose Google sign-in) and Cloudflare (connection metadata for the sign-in human check). Those are the only transfers outside the EEA, and they are listed with the rest in Sub-processors below. Transactional email is handled in France. The privacy notice covers the transfer safeguards.
- Network: all traffic is terminated at a managed edge with DDoS protection.
- Backups: encrypted, managed by the hosting provider, and deliberately short-lived: about a week of daily snapshots plus roughly two weeks of point-in-time recovery. There is no long-term archive, so a deletion clears the backups as those copies age out.
- Tenancy: fjordFIRE is a multi-tenant application; data isolation is enforced at the application layer, with row-level security at the database as a second line of defense. All data access is scoped to the relevant user or household context.
Sub-processors
Vendors that process personal data on our behalf. We use the smallest viable set; each has a specific role and a documented data-processing agreement.
- Railway: application + database hosting (EU region). This is where account data lives.
- Mistral: European LLM provider for the in-app AI companion. What it receives is a derived snapshot, not your ledger. The assistant is grounded on aggregate figures computed before the call: household totals, pillar balances, runway months, FI date, per-member summaries. Individual accounts and the transaction-level history are not in the payload, which is why it can tell you your emergency fund covers 3.7 months without being sent the accounts that make it up. Under our data-processing agreement with Mistral, conversations are excluded from model training. We keep conversations only so you can scroll back through them: a thread is deleted 30 days after its last message, and you can clear one thread or your whole history sooner from inside the app.
- Sweego (MINDBAZ SAS, Lille, France): transactional email, so it receives your address and the contents of sign-in codes and notifications. Processing is in France, on European infrastructure, and nothing leaves the EEA. Worth knowing what those contents actually are: fjordFIRE emails carry no financial detail by design. Reminders, digests and alerts say there is something to look at and send you into the app to see it, so balances, account names, figures and goal details stay inside the product. Every email states this in its own footer.
Identity and security services
Sign-in and abuse prevention. These see authentication or connection metadata, not the account data we hold.
- Google OAuth (Google LLC, US): optional sign-in provider, only invoked for users who choose it. Google acts as the identity provider, not a processor of your fjordFIRE data. We rely on its EU-U.S. Data Privacy Framework certification for non-HR data; if that framework is invalidated, the transfer falls back to Standard Contractual Clauses.
- Cloudflare Turnstile (Cloudflare, Inc., US): bot protection on sign-in and account forms. Inspects connection signals to tell humans from bots; does not receive account data. We rely on its EU-U.S. Data Privacy Framework certification for non-HR data; if that framework is invalidated, the transfer falls back to Standard Contractual Clauses.
Reference data sources
Public data feeds. No personal data is sent to these.
- exchangerate-api.com: daily FX rates inside fjordFIRE (currency code → USD).
- World Bank Open Data API: per-country inflation (10-year geometric-mean CPI) and PPP price-level data, cached on our side.
- Frankfurter: ECB-anchored daily FX rates for the public calculators on this website.
Analytics
- Umami: privacy-friendly analytics, no personal identifiers.
Monitoring and error diagnostics
- BetterStack (EU): uptime and scheduled-job monitoring. It sees only whether a health-check URL responds and whether a scheduled job has checked in. No account data, no page contents, no personal information.
- Error diagnostics (self-hosted GlitchTip): an open-source error tracker running on our own EU infrastructure, not a third-party service. Reports are scrubbed before storage: request bodies, cookies, authentication headers, and query strings are removed; email addresses and long numeric identifiers are masked; the user is reduced to an internal account ID; IP addresses are truncated. Reports are automatically deleted after 90 days. No session replay or screen recording.
These lists are the source of truth. Changes are reflected on this page and in the privacy notice.
What we do not have
- No bank-credential vault. There is no integration that asks for them.
- No third-party advertising or tracking SDKs (no Google Analytics, no Facebook pixel).
- No session-replay or screen-recording.
- No machine-learning training on user data.
Information security management
- Internal financial-correctness audit: the math layer is reviewed line by line against the formulas, FX paths, inflation handling, edge cases, and consistency rules it should obey. Findings are tracked and patched in the changelog.
- Defense-in-depth: row-level security at the database, parameterised queries throughout, strict input validation at the application boundary, principle-of-least-privilege on every internal interface.
- Code review: changes are reviewed against the OWASP top-ten and an internal checklist before deploy. We are a small team, so this is a practice rather than a gate enforced by tooling: worth saying plainly rather than implying separation of duties we do not enforce.
Operations
- Access control: production access is restricted to named individuals on a least-privilege basis, requires multi-factor authentication, and is logged.
- Patching: dependency updates are raised automatically by Dependabot and reviewed before merge; security advisories trigger out-of-band patches.
- Incident response: two different clocks, and they are worth separating. If a breach is likely to put you at high risk, we tell you without undue delay. If it is reportable, Datatilsynet gets it within 72 hours of us becoming aware. The 72-hour figure is the regulator’s deadline, not yours: you hear from us as soon as we know enough to tell you something useful.
Reporting a vulnerability
Found something? Email contact@fjordfire.com. We aim to acknowledge within three business days, keep you informed during triage, and will not pursue legal action against good-faith research carried out on the terms in section 3 of the terms: test only against households you made yourself, leave everyone else’s data alone, and tell us before you tell anyone else. You may publish 90 days after reporting whether or not we have fixed it, and that does not forfeit the protection. There is no bounty and no payment; this is a free project.
This page is updated whenever the underlying mechanisms change. Material product changes are recorded in the changelog.
