← All posts

Where encryption stops: the limits of our own privacy claim

1 August 2026 · 9 min read · TruMint


Parts 1 and 2 described a system where your financial values are ciphertext everywhere except inside one attested service. That is true, and it is not the whole picture. Encryption at rest answers exactly one question — what does someone get if they steal the storage — and a real system has other doors.

This post is the list of those doors. We wrote it because the version of this series that omits it is the version that gets taken apart in public by the first competent reader.

How this list was produced
We ran an adversarial review of our own published claim, testing it against live production rather than against the design documents. It found seven issues serious enough to falsify the claim as written. Most are now fixed; the ones that are not are below, described as problems rather than as roadmap items.
Updated 2026-08-26
Two limits this post first described as unfinished have since shipped, and we update the page when that happens rather than let it drift. Account takeover is now detected: the reconciliation job described in §3 is live and emails you if your sign-in is changed out of band. And the running image now reports the source commit it was built from (see the scorecard). What is still genuinely not done — reproducible builds, an externally-anchored release log, and the AI-provider retention exemption — stays marked that way below.

1. The server sees plaintext while it works for you

This is structural, not a bug. Computing Section 104 pools, matching transfers and answering portfolio questions all require the numbers. The plaintext exists in the memory of an attested enclave, for the duration of a request, and nowhere else — not on disk, not in a backup, not in a log. If you want a product where the server genuinely cannot compute on your data, you want a different category of product, and you should be suspicious of anyone selling you both.

2. Using the AI features sends data to Google

Ask TruMint, P60 extraction and automatic spending categorisation run on Gemini via Vertex AI in the EU. When you use them the relevant data leaves our systems: your question and the figures behind the answer, the document you uploaded, or the merchant text on a transaction.

   enclave                                     │  Google Vertex AI (europe-west1)
   ─────────────────────────────────────────────┼──────────────────────────────
   encrypted at rest                            │
        │ decrypt                               │
        ▼                                       │
   tool results  ── holdings, balances,   ──────┼──►  model
                     merchants, tax figures     │
   your question ─────────────────────────  ────┼──►
                                                │
   NOT sent: your DEK, other users' data,       │  no training on your data
             anything you did not ask about     │  30-day abuse-monitoring window
What crosses the boundary on an assistant turn. Tool results are decrypted specifically in order to be sent.

What is true: it is EU-resident, covered by data-processing terms, and never used to train models. What we will not claim: zero retention. By default Google keeps prompts and responses for up to 30 days for abuse monitoring. An exemption exists; we have not obtained it yet, so today that 30-day window applies to us. We will change this sentence when the exemption is granted, not when we apply for it.

Two things we fixed while writing this. Bank descriptors sometimes contain the name of the person you paid — a landlord, a friend splitting rent. That third party never agreed to anything, so person-like descriptors on bank rails are now withheld from the model entirely and categorised locally. And the classifier had a fallback to the public Gemini API that would have engaged silently on a misconfiguration; it now refuses to run rather than send your data outside the agreement.

3. An administrator can still take over an account

This is the sharpest item, and the one most likely to be missing from a competitor’s version of this page.

Attestation binds decryption. It does not bind authentication. Holding the administrative credential for our identity provider, one can reset an account’s password, change its email, or remove its second factor — and then sign in as that user. At that point the enclave decrypts and serves the data, exactly as it would for the real person, because as far as the system is concerned it is the real person. Two-factor authentication is now mandatory for new accounts and offered to all, which raises the bar: with a second factor enrolled, a password reset alone is not enough — the factor has to be removed first, and that removal is exactly what we now detect.

PathStatus
Mint a session token directly for any account (silent)Closed — such sessions are refused in production
Reset the password / change the email, then sign inPossible, and now flagged to you by email within hours (reconciler)
Remove an enrolled second factor firstPossible, and detected — an out-of-band factor removal is flagged to you
Detect the above from cloud audit logsDoes not work — so we built our own; see below

The silent path is closed: a token minted with administrative credentials carries a marker that production now rejects outright, at every entry point, and the rejection is part of the attested image — so removing it means shipping a new digest, which is logged and alerted.

The loud path remains. Our planned answer was to enable cloud audit logging and alert on administrative account changes. We tested that assumption and it failed: we enabled the logs, performed the exact administrative mutation, and no audit entry appeared — while unrelated key operations logged normally in the same window. Administrative SDK calls simply do not surface there. So we built application-level reconciliation instead, and it is now live: the app records every account change it legitimately made, a job runs every few hours comparing that against the identity provider’s actual state, and any change with no matching record — a factor removed, an email swapped — is flagged to you by email, not only to us. We proved it end to end by performing the real administrative factor-strip against production and confirming the alert fired. A related change since this post first published: the standing administrative key that used to sit on a developer machine has been deleted; that access is now a short-lived, individually-logged impersonation, so using it leaves a trail even though the identity provider’s own logs do not.

  in-app change (you)               out-of-band change (operator)
  enrol · recover · edit            Admin SDK: strip 2FA, swap email
        │                                    │
        │ app records it and                 │ identity-provider state
        │ re-baselines — signed              │ changes, but writes NO
        │ with your key                      │ cloud audit-log entry
        ▼                                    ▼
  ┌────────────────────────────────────────────────────┐
  │  reconciler · every few hours · inside the enclave  │
  │  diff live auth state   vs   the recorded baseline  │
  └───────────────────────┬────────────────────────────┘
                          │
             match ◄──────┴──────► no match
              │                       │
             ok          ┌───────────┼────────────┐
                         ▼           ▼            ▼
                    flag account  email YOU    alert us
How a silent account change becomes a loud one. The baseline is signed with your own key, which only the enclave can unwrap — so an operator can rewrite the stored record but cannot forge a match to it.
So the accurate sentence is
We cannot read your data, and we cannot access your account silently. We can still take an account over in a way you would notice — and, now, in a way your own account flags to you by email. The residual we have not closed is prevention: today we detect the takeover, we do not yet make it impossible.

4. Structural metadata stays readable

Covered in Part 1, repeated here because it belongs in a list of limits. Identifiers, dates and a few coarse enums are not encrypted, because the database has to filter on them. Someone with the database learns activity shape — how many transactions, in which months, in which broad categories — but not amounts, counterparties, holdings or values.

One subtler consequence: because AES-GCM preserves length and we compress before encrypting, the size of a ciphertext correlates loosely with the size of the plaintext. A seven-figure salary is distinguishable from a four-figure one by length alone. We have not fixed this; padding costs storage on every field and we would rather tell you than pretend.

5. Where the bytes physically sit

Keys are in London. The enclave runs in London. The database is a US multi-region and object storage is US — so ciphertext is stored in the United States, while everything needed to read it stays in the UK. AI inference runs in the EU. We think this is a defensible arrangement and we would rather state it plainly than let “UK keys” imply UK storage.

The scorecard

ClaimStatus
A database breach yields no financial valuesTrue
Backups and logs contain no financial valuesTrue
Our administrator cannot decrypt your dataTrue — verified against live infrastructure
Amounts, names, descriptions and balances are encryptedTrue
Plaintext metadata does not reveal your financial positionTrue
Our administrator cannot access your account at allFALSE — a visible, now-detected takeover is possible; prevention is not
No third party ever sees your dataFALSE — the AI features send data to Google
Zero retention at our AI providerFALSE today — 30-day abuse-monitoring window applies; exemption not yet obtained
You can verify the running image matches our sourcePartly — it reports its source commit and every release is hash-chained; independent rebuild is not yet possible
We would rather publish the FALSE rows ourselves than have them found.

Why publish this

A trust page that lists only the good news is a liability: every omission is something a reader can discover, and discovering it costs more trust than the original claim ever bought. The three rows above that are not green are the ones we would want to know about if we were choosing where to put our own financial data.

If you find something we have missed, we would genuinely like to hear about it — [email protected]. We do not pursue researchers acting in good faith, and this series exists because we took our own claim apart first.

A three-part series on what TruMint can see
  1. Part 1What we can and cannot read
  2. Part 2The key that refuses to talk to us
  3. Part 3Where it stops (you are here)

See it for yourself: explore a sample portfolio. No signup, no bank link.

Try the live demo