Security & data handling
Specifics rather than adjectives. Everything below is a description of what the system does today, including the parts that are not finished.
What Grubless can do with your accounts
It reads. It cannot move anything. Grubless never asks for a private key, a seed phrase or a withdrawal permission, and no part of the product would accept one. Wallets are tracked by public address, which grants no ability to spend.
Exchange connections use API keys you create and scope yourself. Read-only is all we need. Nothing in Grubless can place a trade or make a withdrawal, whatever permissions a key happens to carry.
Wise connects with a read-only API token you create on wise.com. It reads your profiles, balances and statements and cannot send money.
Up is the exception, because Up offers no read-only token: its personal access token can also recategorise and tag your transactions and set up webhooks that send new transactions to a web address. It cannot move money. Grubless only ever reads with it, stores it encrypted, and never sends it back; you can revoke it in the Up app under Data sharing at any time.
How credentials are stored
- Passwords: scrypt, with a per-account random salt. We never store or transmit your password, and cannot recover it.
- Exchange API credentials: encrypted with AES-256-GCM before they are written to the database. They are never sent back to any client — not the web app, not the CLI, and not an administrator's screen. Once entered, a credential can be replaced but never read back.
- Session and API tokens: stored only as SHA-256 hashes. A stolen database copy yields no usable token. An API token's plaintext is shown exactly once, at creation, and never again.
- In transit: TLS everywhere. Plain HTTP is redirected, and the site sends
Strict-Transport-Securityso your browser will not try HTTP for it again.
Keeping accounts apart
Every request is scoped to the requesting account at the database query, not by filtering results afterwards. That boundary is covered by a dedicated integration suite that runs against a real database. The honest reason it exists: an audit of every route found three cross-tenant defects, which we fixed.
Within an account, entity access is role-based: owner, preparer or viewer.
What we can see
There is an operator console for support and billing. Four things constrain it, and they are deliberate:
- Access requires two independent factors — a database flag and an email allowlist set at deploy time. Either alone does nothing, and there is no path in the product that can grant either.
- It shows accounts, plans, entity and transaction counts, each account’s approximate total value (rounded to the nearest US$1,000, so we can prioritise support), and the job queue. It does not show transaction contents. A billing question does not need to see your disposals.
- No impersonation. We cannot log in as you. It is the most requested capability of its kind and we have deliberately not built it, because everything done while impersonating gets attributed to the customer — it makes the audit log lie.
- Every access is logged, including reads. After an incident the question is what an operator looked at, and a write-only log cannot answer it.
Where it runs
Australia — Fly.io's Sydney region — for the application, the database, the job queue and the backups. Backups are taken daily and retained on a rolling basis.
The full list of third parties that receive data, and what reaches each, is in the privacy policy.
Signing in
A password is the weakest credential on the account, and everything here exists because of it. All of it is optional and all of it is free.
- Passkeys and hardware security keys (WebAuthn) — a synced passkey from your phone or password manager, or a YubiKey. This is genuinely stronger than a code, not just different: a six-digit code can be read out to somebody claiming to be support, whereas a key signs only for the real origin, so it will not respond to a lookalike domain at all. Register as many as you like.
- Authenticator apps (TOTP) — scan a QR code with any app. More than one device can be registered, so a phone can be replaced without turning the protection off in between, and each can be removed on its own.
- Recovery codes — eight single-use codes, shown once, stored only as hashes. They are the way back in when a device is lost.
- A password alone yields a half-open session that can do exactly one thing: finish signing in. It cannot read your ledger, and an API token can never turn two-factor off.
What we have not finished
A security page that lists only strengths is not informative. As of 22 September 2026:
- No third-party security audit has been carried out, and there is no SOC 2 report. We would rather say so than let the absence of a statement imply otherwise.
- No committed uptime guarantee — see the terms.
- Two-factor is not compulsory. We urge it rather than require it: a wall in front of connecting your first account protects something that, at that moment, holds nothing. That is a deliberate trade-off, and it means an account without it is protected by a password alone.
These are on the roadmap rather than accepted permanently, and this list will change as they land.
Reporting a vulnerability
If you have found a security problem, email security@grubless.io. Include enough detail to reproduce it. We will acknowledge within 3 business days and tell you what we intend to do.
Our undertaking: we will not pursue legal action against anyone acting in good faith under this policy, we will keep you informed while we fix it, and we will credit you if you would like us to. There is no paid bounty programme — we would rather promise something we can honour.
What we ask: report privately and give us a reasonable chance to fix it before publishing; use only your own accounts and test data; do not access, modify or destroy another customer's data; and stop at proof of concept rather than extracting records to demonstrate impact.
A machine-readable version of this is at /.well-known/security.txt.
If we have an incident
We assess any suspected breach against the Notifiable Data Breaches scheme (Part IIIC, Privacy Act 1988) within 30 days. Where a breach is likely to result in serious harm, we notify affected customers and the Office of the Australian Information Commissioner as soon as practicable.
Notification goes to the email address on your account. We will say what happened, what data was involved, what we have done, and what you should do — in that order, and without waiting until we have a complete picture if waiting would leave you exposed.