The security model for giving an AI access to your books
Every table holding user data has row-level security forced on, scoped by a user id set inside the transaction. API keys are stored as SHA-256 hashes. If the database connection uses a role that can bypass row-level security, the server refuses to serve requests at all rather than serve them with isolation silently inert.
Connecting an AI assistant to your financial records is a real trust decision, and it deserves a specific answer rather than the word "secure". Here is what is actually enforced, where, and what it does not cover.
What is actually enforced
- Row-level security is enabled and FORCEd on every table holding user data.
- Request scope is set inside the transaction, and every policy reads it.
- The server throws rather than serving over a connection whose role can bypass row-level security.
- That check lives inside the function all user-data access goes through, so a caller supplying its own connection cannot skip it.
- API keys are stored as SHA-256 hashes and can be revoked.
- Cross-tenant isolation was verified live across every tool and every server action, not inferred from the policy definitions.
Tenant isolation is a database property, not a query convention
Row-level security is enabled and FORCEd on every table that holds user data. Forced matters: without it, the table owner is exempt from its own policies, which is the quiet way this kind of protection stops working.
The scope comes from a user id set inside the transaction, which every policy reads. So a query that forgets its WHERE clause returns nothing rather than returning everything, and correctness does not depend on every author of every query remembering the same thing.
The refusal that is the most useful part of this
Row-level security is inert for a database role that can bypass it — and the default administrative role on a managed Postgres instance usually can. Connect with those credentials and every policy above becomes decoration. Nothing breaks. No error appears. The isolation simply is not there.
So the server checks the role it is connected as, and if that role can bypass row-level security it throws rather than serving. Not a warning in a log nobody reads: a refusal to handle requests.
The check lives inside the function that every access to user data goes through, rather than at connection setup, so a caller that supplies its own database handle cannot route around it. A guard only some code paths reach is not a guard.
The practical cost of this design is that a misconfigured deployment does not start. That is the intended trade.
Keys
Access is by bearer API key, minted from your account and shown once. Keys are stored as SHA-256 hashes, so the stored form cannot be turned back into a working credential, and a key you revoke stops working immediately.
A key is the whole of the authority it grants. Anything holding it can do anything the tools can do, which is the honest way to describe the current state — see the limits below.
What this does not cover
- API keys are all-or-nothing. There are no read-only or scoped keys yet, so a key handed to an assistant can do everything the tools can do.
- Key minting is not rate-limited per account, so nothing stops a large number of keys being created.
- Standard security response headers are not yet set.
- BalanceMCP is not a bank and holds no funds, but it does hold a detailed picture of your finances, and the assistant you connect is a third party with its own data handling.
Common questions
- Can another user see my books?
- No. Isolation is enforced by database policies rather than by application filters, and it was verified by attempting cross-tenant access through every tool rather than by reading the policies and concluding they looked right.
- What can the AI assistant see?
- Whatever the tools return for your books, when it calls them. It has no standing access to your data — it holds a key and makes requests, and every request is logged.
- What happens if I revoke a key?
- It stops working immediately. Anything using it starts getting authentication failures on the next call.
- Is my data encrypted?
- Traffic is over HTTPS and the database is hosted on managed Postgres with encryption at rest. There is no additional application-level encryption of ledger contents, because the tools have to read it to compute reports.
Checked against the implementation on 2026-08-09.