Security

What we do with your financial data.

Written for someone who has to justify this choice to a partner or an auditor. Everything in the first section is in place today. Everything we have not done yet is in the second section, named plainly rather than left to inference.

Each claim below is paired with a test that fails if the mechanism behind it is removed: the claims and their proofs.

In place today

How the product is built

Bank access

Read-only, through an aggregator

Bank connections go through Plaid. You authenticate with your bank inside Plaid's own flow — we never see or store your bank credentials, and we hold no ability to move money. We request transaction data only; the access is read-only. Today that integration runs against Plaid's sandbox while we complete production access, so a live connection is not yet available.

Encryption

Encrypted in transit

Every connection — browser to app, app to database, app to the accounting engine — is TLS-encrypted. Our database provider encrypts data at rest on its managed infrastructure. Where a connector requires a stored API token, we encrypt it with AES-256-GCM using a key held only in the server environment, and if that key is not configured we refuse to store the token at all rather than keep it in the clear.

Isolation

Row-level security in Postgres

Your data lives in Postgres with row-level security enabled on every table that holds it. The policies scope each row to the account that owns it, enforced by the database rather than by application code — a query that forgets to filter still returns nothing that isn't yours.

Audit trail

Append-only by construction

Rule versions are append-only: editing a rule creates a new version with provenance, and a database trigger blocks UPDATE and DELETE on the old one. Imported source records are write-once — the trigger refuses an edit even from our own service credentials. Postings are insert-only and the database rejects one that carries a failed review or that doesn't balance.

Isolation

The re-derivation never reads your ledger

When we reproduce your month from the bank rows, your general ledger is not an input. It is opened once, afterwards, only to compare against. That is provable rather than promised: there is a test that runs the engine with the ledger removed and asserts identical output. It matters because next month there is no ledger, and a re-derivation that quietly leans on one is a demonstration rather than a close.

Control

A human approves every posting

The engine drafts; it never posts. An independent check re-derives each entry and a failed check blocks posting entirely. The posting itself is an explicit action recorded against the person who took it, alongside the rule version that produced the entry. AI is used to help author rules in plain English — never to compute or book a number.

Accounting system

QuickBooks is read-only, by construction

The QuickBooks client has one function that makes a request and it is a GET. There is no create, no update, no delete, no batch — nothing posts to QuickBooks, ever, because there is nothing there to call. A test fails the moment that stops being true, and disconnecting deletes the stored tokens rather than marking them revoked. The connection runs against an Intuit sandbox while their app review is under way, so it is not open to accounts yet; a file export is the way in until it is.

Secrets

Never in the browser

API keys and service credentials are read from the server environment and never reach the client bundle. The browser never talks to a bank, to our accounting engine, or to a model provider directly — every such call is made server-side.

In progress — not yet true

What we have not done yet.

We would rather you learn this here than discover it in diligence.

SOC 2

Readiness, not certification

We are working toward SOC 2 Type II readiness. We have not completed an audit and hold no SOC 2 report today. If your process requires one, we are not there yet — ask us where we are and we will tell you specifically.

Infrastructure

Early-stage hosting

The product runs on managed infrastructure (Vercel, Supabase, Railway) on entry-level plans. Backups are those the providers offer by default, and we have not yet completed a documented restore test. Formal backup and disaster-recovery commitments come with the upgrade to paid tiers.

Reviews

No third-party audit yet

No external penetration test or security audit has been performed. There is no formal incident-response commitment or uptime SLA. We are a small team building in the open about it.

Your data

What we store, how long, and how to end it.

Retention

Seven days, unless you convert

Trial uploads carry their own deletion date, stamped when they are written, and a scheduled sweep honours it. Your date is shown on your data page — you do not have to ask us what it is, or trust that we remembered.

Deletion

Yours to end, immediately

One action on your data page removes your files, their stored originals, every transaction read out of them, everything drafted from them, and your rules. It happens on the request, not on a queue, and it cannot be undone.

Evidence

Two things survive a delete

Your record of agreeing to the terms, and the record of the deletion request itself. Both are evidence about what was agreed and what you asked for. Neither contains any of your financial data.

An upload is parsed on our server into rows. We store the parsed transactions, the source record for each one (kept verbatim so a number can always be traced back), the original file in private per-account storage, the rules you approved, and the entries drafted from them.

It is your data. Ask us to delete it and we will, and you can delete an imported period or a saved close yourself from within the product. See the privacy policy for the full list of what is collected and who processes it.

Contact

When something fails, quote the id

Every failure this product can show you carries a short id — REQ-9BEBRM, say — and says to quote it. It has somewhere to go: abe@attest.finance. The id is how we find the exact request in our logs, along with the accounting system's own id for it, so you do not have to describe what went wrong from memory. It identifies a request, never you, and it carries none of your figures.

Contact

Reporting a vulnerability

Email abe@attest.finance. Tell us what you found and how to reproduce it; we will acknowledge you and keep you posted on the fix. We will not pursue action against good-faith research that avoids privacy violations, data destruction, and service disruption.