Security
Summary. The app never sees a bank username or password. Plaid and SimpleFIN Bridge hold those; the app only ever holds a read-oriented access token issued by them. Sign-in is Google OAuth, and only one email address is allowed through.
1. Bank credentials are never handled by this app
This is the important one, and it is true of both aggregators:
- Plaid. Institution credentials are entered by the operator inside
Plaid Link, hosted by Plaid. The app never receives them. What
the app receives back is a
public_token, which it immediately exchanges with Plaid for anaccess_token. There is no code path in this application that accepts, transmits, or stores a bank username or password. - SimpleFIN Bridge. The operator authenticates at the SimpleFIN Bridge himself and claims a setup token there, outside this app. The resulting access URL — which carries HTTP Basic credentials issued by SimpleFIN, not by any bank — is then stored in the app as a Cloudflare Workers secret. The app never sees the bank login.
Both integrations are read-only in practice: the app calls only
data-retrieval endpoints (/accounts/get, /transactions/sync,
/investments/holdings/get, /investments/transactions/get at Plaid;
/accounts at SimpleFIN). It has no ability to move money, initiate
payments, or modify anything at a financial institution. The Plaid
products requested are transactions and investments; no payment,
transfer, or auth product is requested.
2. How tokens are stored
- Plaid
access_tokenvalues are stored in the app's private Cloudflare D1 database (plaid_itemstable), which Cloudflare encrypts at rest. The application does not add its own application-layer encryption on top of that — stated plainly rather than overclaimed. - The SimpleFIN access URL is stored as a Cloudflare Workers secret, not in the database, and is never logged. Error messages from the SimpleFIN client are written so the URL is not leaked into logs.
- Plaid client ID and secret, the Google OAuth client secret, the
session signing secret, the Google API key, and the Plaid webhook
token are all Cloudflare Workers secrets, set with
wrangler secret put. None are in the source repository.
3. Authentication and access control
- Sign-in is Google OAuth 2.0, requesting only the
openidandemailscopes. - The OAuth
stateparameter is bound to a short-lived signed (HS256 JWT) cookie to prevent CSRF on the callback. - After Google returns an email address, it is checked against the
ALLOWED_EMAILSallowlist. A non-matching address gets an HTTP 403 page and no session. - Session cookies are
HttpOnly,Secure, andSameSite=Lax. - The app is served only over HTTPS on a Cloudflare custom domain;
workers.devand preview URLs are disabled.
4. Webhooks
Plaid webhooks are accepted at a single endpoint and rejected unless the request carries the correct shared token, which is stored as a Cloudflare secret.
5. Data retention and destruction
Deleted receipts are soft-deleted, then permanently destroyed — database row and R2 object both — by a scheduled job that runs daily at 05:00 UTC on anything soft-deleted more than 30 days earlier. Each purge run is written to the app's audit log.
6. What is deliberately not claimed
No security certification is claimed. There is no SOC 2 report, no ISO 27001 certification, and no third-party penetration test. This is a personal application run by one person, documented honestly.
7. Reporting a vulnerability
If you believe you have found a vulnerability in this app or this site, email rolotrealanis@gmail.com before disclosing it publicly. There is no bug bounty, but reports are taken seriously and acknowledged.