Trust centre

Built for finance teams who can't afford surprises

This page describes the security controls Fin-Central implements today, stated at the scope they actually operate at. Where a control is narrower than the industry shorthand implies, we say so on this page rather than in a follow-up call.

Data handling

Fin-Central reads accounting data via OAuth (Xero, QuickBooks, Sage) or CSV/XLSX import. We do not replace your ERP — your ledger of record stays in place. Xero and Sage are connected with read-only scopes. QuickBooks is the exception and we will not blur it: Intuit publishes no read-only accounting scope, so the only scope that grants ledger access (com.intuit.quickbooks.accounting) also grants write access. Fin-Central issues only read calls against QuickBooks, but the authorisation you grant is write-capable, and you should assess it on that basis rather than on our intent.

Encryption — exactly what is covered

We state this precisely because the usual one-line version is misleading. Application-level AES-256-GCM encryption is applied to connector OAuth access and refresh tokens (AccountingConnection) and to your 2FA secret (User.mfaSecret) — see src/lib/connectors/credentials.ts. Passwords are bcrypt-hashed and 2FA recovery codes are SHA-256 hashed, both one-way and never recoverable. Your ledger data — invoices, bills, bank transactions, trial balance, forecasts and the audit log — is NOT encrypted by the application; it is stored as ordinary database columns, because every page filters, joins and aggregates over them in SQL. At-rest protection for that data comes from the database and disk encryption of the environment it is deployed into, which is a deployment prerequisite we document rather than a control we provide. Traffic is TLS in transit.

Key management and rotation

Token encryption uses a versioned key ring: the first configured key encrypts, all configured keys are tried on decrypt, so a key can be rotated with no downtime and no re-encryption migration. The token key is configured separately from the session-cookie secret, so rotating one need not lock you out of the other — but note that if no dedicated token key is set, the ring falls back to deriving one from the session secret, and the application logs an error saying so on every start. Managed-KMS envelope encryption (AWS KMS or Google Cloud KMS) is available and must be switched on deliberately: set KMS_PROVIDER and KMS_KEY_ID, then generate a wrapped data key with scripts/kms-wrap-dek.ts. It is off by default, and when it is off the token key is a local one held in the deployment's environment. If a managed KMS is configured and then cannot be reached, the application fails the operation and logs it rather than quietly reverting to the local key.

Access control

Five tenant roles — OWNER, FINANCE_ADMIN, PREPARER, REVIEWER, READ_ONLY — enforced server-side on every mutating route. Sign-off is separated from preparation: a PREPARER cannot approve their own cash-flow overrides. Every CSV export resolves against an exhaustive capability table with no permissive default, so an export added later is denied until someone grants it explicitly. Tenant isolation is enforced from the server session on every query — the acting company is never read from the request.

Two-factor authentication

Self-service TOTP enrolment (RFC 6238) from any authenticator app, enforced as a second step at login. Single-use recovery codes can be generated for device loss; only their hashes are stored, and using one is recorded in the audit log.

Audit trail

Logins, logouts, role changes, overrides and their approvals, close actions, uploads, billing events, exports, and refused exports are written to a per-tenant audit log with actor, action, entity and timestamp. The log records other users' actions, so reading or exporting it requires a tenant admin — a READ_ONLY or PREPARER user cannot pull it. The log is kept for 13 months — a full audit cycle plus a month of overlap so any period can be compared against the same period last year — after which older entries are deleted. Entries that evidence a data-rights action are exempt from that and are never deleted: account erasures, tenant deletions, data exports, and refused exports or permission denials. Rejected import rows are logged as counts and reasons only; the rejected row content itself is returned to the uploader in the response and is not written to the log.

Retention, and what deletion actually means

Every retention period is stated exactly, on /legal/privacy, and every one of them is the period the deletion job applies — the two are checked against each other by the test suite, so the policy cannot go on describing a period the software has stopped applying. The short version: for the ledger we process on your behalf we are the processor and you keep your own statutory six-year records in your accounting system, so we hold a shorter working copy rather than a second archive. Audit evidence files and the text extracted from them are deleted 90 days after an engagement closes; bank transactions at 24 months; the vendor lookup cache at 12. Supplier bills (36 months) and the general ledger and trial balance (27 months) are deliberately kept longer because the three-year spend comparison, prior-year comparatives and audit-pack opening balances depend on them. Deletion removes the database rows AND the underlying files, and is followed by a storage reclaim so the deleted content is no longer readable in the database file — a plain DELETE leaves the payload on disk in both SQLite and PostgreSQL. Two limits we would rather state than gloss: database backups taken before a deletion still contain it until they age out on their own schedule, and the deletion job is run on a schedule by the operator of this deployment rather than by a timer inside the application.

Your data rights, self-serve

Any user can download the personal data held about them (profile, memberships, their own activity) as JSON, and can erase their own account, from Settings → Security. No support ticket, no waiting on us.

Fail-closed production boot

In production the application refuses to start with a missing or too-short session secret, or without a database URL — a forgeable session is treated as worse than an outage. It warns loudly on SQLite in production, partially-configured billing, and connectors running without a dedicated encryption key.

AI & Finance Copilot

Copilot routes questions to ledger-grounded tools with citations. Optional LLM synthesis receives only tool output — never raw passwords or tokens. Your data is not used for training. With no LLM key configured the assistant still answers, using a deterministic ledger-grounded router.

Subprocessors

  • Xero / Intuit / Sage — accounting data source (your OAuth)
  • OpenAI, Anthropic or OpenRouter (optional) — LLM synthesis, only when a key is configured
  • Resend (optional) — weekly digest email, only when a key is configured
  • Stripe (optional) — billing, only when configured

Certifications: none

We hold no security or privacy certification, attestation or independent audit report of any kind, and we are not going to imply otherwise by naming one as a roadmap item. What we offer instead is the list above: specific, named, and checkable in the source. If your review process requires a certified supplier, we do not meet that bar today.

Known limitations, published

We publish the gaps as well as the controls — encryption scope, per-instance rate limiting, application-enforced (not database-enforced) tenant isolation, and more. Ask us for docs/KNOWN-LIMITATIONS.md and docs/SECURITY-OVERVIEW.md; they are written for your IT reviewer, not for marketing.

Status of this service

The operator's registered legal details are not yet published, so the terms and privacy policy are drafts and no contract is offered or implied. Security reviewers are welcome to assess the controls above in the meantime — the contact address on the legal pages reaches us for questionnaires and technical questions.