Security
Last updated: 26 August 2026.
Connecting LedgerWatch means giving a small, unknown vendor read access to your clients' supplier banking data. That deserves scepticism. This page describes what the software actually does, in enough detail to check, and ends with a list of things LedgerWatch is not. Nothing here is aspirational: it describes the system as it is deployed today.
What LedgerWatch reads from Xero
LedgerWatch requests four OAuth scopes from Xero, and no others:
-
accounting.contacts.read— read access to your contacts, which is how we read the bank account details we monitor. -
accounting.settings.read— requested for one purpose only: to read your organisation's country, timezone, base currency and short code, so dates, currency amounts and bank field labels display correctly for your region. Xero grants this scope more broadly than we use it — it also allows reading your chart of accounts, which LedgerWatch never requests and never stores. -
offline_access— a refresh token, so the scheduled check can run every 15 minutes without you being logged in. -
openid profile email— standard sign-in scopes used to complete the connection.
Every scope is read-only. LedgerWatch does not request any write scope, so it cannot create, change or delete anything in your Xero organisation — not a contact, not an invoice, not a payment. It has no access to bank feeds and no ability to initiate, approve or alter a payment. If it were fully compromised tomorrow, an attacker could read supplier bank details; they could not move money through Xero.
What is stored, and what is encrypted
For each contact in a connected organisation, LedgerWatch stores the contact's name, whether Xero flags it as a supplier, and its bank fields: the bank account details, and the batch payment account number, account name, code and reference. It stores a history of every change detected to those fields, and — where Xero records it — the name of the person who made the change. It also stores your account email address, the email addresses you nominate to receive alerts, and the Xero access and refresh tokens for your connection.
Encrypted at rest using AES-256-GCM with a separate random initialisation vector for every value: all five bank fields on every contact snapshot, the before and after values on every recorded change, the shared account value behind a duplicate-account finding, and both Xero tokens.
Not encrypted, and stored in the clear in the database: your account email address, organisation names, contact names, the name of whoever Xero records as having made a change, the notes you write when reviewing an alert, your nominated alert recipient addresses, and the log of which alert emails were sent.
What that encryption does and does not protect against. The encryption key is held as an environment secret on the hosting platform, separate from the database file itself. So encryption at rest protects against someone obtaining a copy of the database or a backup file without also obtaining the running environment — a stolen backup, a misplaced snapshot, a compromised storage bucket. It does not protect against a compromise of the running application or the hosting account, because any process that can read the database can also read the key. Encryption at rest is a real control against a specific, common failure. It is not a defence against an attacker who is already inside.
Where it runs and where backups live
The application and its database run on Fly.io in Sydney, Australia. All traffic is served over HTTPS; plain HTTP requests are redirected. A snapshot of the database is backed up once a day to Cloudflare R2 in Singapore, kept for 30 days, and then deleted automatically.
Two other providers handle data on our behalf: Stripe processes subscription payments and holds your card details directly — LedgerWatch never sees or stores a card number — and Resend delivers our email. Alert emails necessarily pass through Resend, which means they contain what the email contains: organisation and contact names, and partially masked account numbers (see below).
How accounts are protected
- Passwords are stored using scrypt with a random per-user salt, at one of the cost settings listed as a minimum in the OWASP Password Storage Cheat Sheet, and verified with a constant-time comparison. We cannot see or recover your password. The minimum length is 8 characters. Each stored hash records the settings it was created with, so when those settings are strengthened your password is re-hashed automatically the next time you log in — you are never asked to reset it, and nothing is left on weaker settings because someone forgot to migrate it.
- Sessions use a signed cookie marked HttpOnly, Secure and SameSite=Lax, valid for 7 days. Resetting your password immediately invalidates every existing session on every device, not just the one you reset from.
- Email verification is required before you can connect a Xero organisation. Verification links are single-use and expire after 24 hours; password reset links are single-use and expire after 1 hour, and requesting a new one invalidates any outstanding link.
- Rate limiting applies to logging in (10 attempts per hour per email address, 30 per hour per IP address), registration and password reset (3 per hour per email address). Failed logins never lock an account, so nobody can lock you out by repeatedly failing to log in as you.
- There is no two-factor authentication yet. Your password and your email account are currently the only things protecting your LedgerWatch account.
Alert emails and the CSV export
Alert emails partially mask account numbers — generally the first two and last four characters, and for New Zealand–shaped account numbers the bank code and the last four digits of the account number — so an email sitting in an inbox does not carry a complete set of bank details. There are two deliberate exceptions, and you should know about both: values of six characters or fewer are shown unmasked, because masking them would either reveal the whole value anyway or leave nothing legible; and if masking the old and new values would produce the same string — hiding the very change being reported — the email shows both values in full instead, because an alert you cannot act on is worse than one that says more than it needs to.
The CSV export deliberately contains full, unmasked account values. That is the point of it: it is the audit artefact you hand to an auditor, a bookkeeper or an insurer as evidence of what changed and that it was reviewed, and it has to stand alone. It is downloaded over HTTPS by a logged-in account owner, and from that moment it is an ordinary file on your machine, with whatever protection your machine and your email have. Treat it as you would a bank statement. Cells that begin with a character a spreadsheet would interpret as a formula are neutralised before export, so opening the file cannot execute anything.
Who at LedgerWatch can see your data
LedgerWatch has an operator portal, protected by a separate password beyond the normal account login, that shows account email addresses, organisation names, contact and alert counts, subscription status and timestamps across all customers. It does not display bank account values. The operator also has administrative access to the hosting environment, and therefore to the database and the encryption key — as the operator of any self-hosted service does. Actions taken in the operator portal are logged; reads are not currently logged.
Deleting your data
You can disconnect a single organisation or delete your whole account from within the app, or by emailing support@ledgerwatch.app from your account address. Deletion cancels any Stripe subscription, attempts to revoke the refresh token at Xero so it can no longer be used, and then deletes — immediately, not on a queue — the connection and its stored tokens, every contact snapshot, the full change history, your alert settings and recipient addresses, any duplicate-account findings, and your account record.
A copy may remain in a database backup for up to 30 days, until that backup ages out of the retention period described above.
Three things are deliberately kept after deletion, and it is fair that you know what they are. First, the log of which alert emails were sent: recipient address, subject line (which can include a contact or organisation name), timestamp and whether delivery succeeded — never the body of an email and never a bank value. It is retained so the question "were we told?" can still be answered about a since-deleted organisation. Second, a record that a first-time summary and weekly digest have already been sent, so that reconnecting the same organisation does not send them again. Third, a record that a Xero organisation has used its one free trial — the organisation's Xero identifier and a timestamp only, with no personal information — so that disconnecting and reconnecting cannot draw an unlimited number of free trials.
Reporting a security issue
Email support@ledgerwatch.app with enough detail to reproduce the issue. You will get a reply from a person. There is no bug bounty and no payment for reports. Please do not test against other customers' data or against the live service in ways that would affect anyone else; if you need an account to test with, ask and one will be arranged.
What LedgerWatch is not
This section matters more than the rest of the page. Everything above describes real controls; none of it changes any of the following.
- It has not been independently audited or certified. There is no SOC 2 report, no ISO 27001 certification, and no third-party penetration test. The security measures described on this page were designed, implemented and reviewed by the same person who wrote the software. That is not the same as independent assurance, and it should not be read as such.
- It is not listed on the Xero App Store. It has not been through Xero's app review process and carries no endorsement from Xero. LedgerWatch is not affiliated with, endorsed by, or sponsored by Xero.
- It is operated by a single person. One sole trader in Australia. There is no security team, no 24/7 on-call rotation, and no second person to notice if something goes wrong while that person is unavailable.
- It carries no insurance covering your losses. If a fraudulent payment is made — whether LedgerWatch detected the change, missed it, or alerted you too late — LedgerWatch does not compensate you for it. See the terms of service.
- It is a monitoring aid, not a guarantee. Monitoring only begins when you connect an organisation; anything already changed before that is what LedgerWatch treats as normal. Checks run every 15 minutes, so a change made and reverted between two checks can be missed entirely. Detection depends on Xero's API being available and accurate. Attribution of who made a change appears only where Xero itself records it. Most importantly, LedgerWatch cannot stop a payment. It tells you something changed. Verifying bank details against a known-good phone number or a trusted document before you pay remains your responsibility, and always will.
If any of this is a dealbreaker for your practice, that is a reasonable conclusion to reach, and we would rather you reached it now than after connecting. If you have a question this page does not answer, email support@ledgerwatch.app.