Sync with your bank, detect subscriptions, track spending, catch anomalies. SQLite database, system keyring credentials, encrypted backups. No cloud. No tracking. No account required.
Connect via SimpleFIN for automatic daily sync, or drag-and-drop CSV exports from Chase, BofA, Amex, Wells Fargo, Capital One.
150+ known services recognized instantly. Pattern detection finds the rest from 3+ recurring charges. Audit accuracy anytime.
Auto-categorized transactions, top spending by category, 3-month rolling averages, outlier badges for unusual months.
Duplicate charges, unusual amounts, price increases on subscriptions, bundle overlap detection (Disney+/Hulu/ESPN+).
Web UI at localhost. Cash flow, commitments, spending breakdown, alerts, 6-month trend. Drill into any number.
Everything the dashboard does, from the terminal. Sync, analyze, export, audit. Script it, cron it, pipe it.
This isn't checkbox security. fin's architecture eliminates entire threat categories by design.
Your financial data never leaves your machine. There is no cloud sync, no telemetry endpoint, no analytics pixel, no account system. The attack surface most finance apps spend millions defending simply doesn't exist here.
Where fin does handle sensitive data, it delegates to proven, audited tools — not homebrew crypto. OS keyrings for credentials. age for backup encryption. Your OS's full-disk encryption for data at rest. Every layer is something you can independently verify.
No cloud storage. No remote API. No user accounts. No login tokens. No session cookies. No telemetry. No analytics. No phoning home. Ever.
Credentials to your OS keyring. Backup encryption to age. Disk encryption to BitLocker/FileVault/LUKS. We didn't build our own — and that's the point.
For the auditors, the skeptics, and the people who read source code before installing anything.
Credentials are stored via the keyring library (v25.0+), which maps to the OS-native secure store: Keychain on macOS, Credential Manager on Windows, Secret Service (GNOME Keyring / KWallet) on Linux. Service name "fin". Falls back to environment variables if no keyring backend is available. Credentials are never written to disk in plaintext.
Backups use age — a modern, audited file encryption tool using ChaCha20-Poly1305. Two modes: passphrase-based (age -p) or recipient public key (age -r age1...). The age binary is invoked as a subprocess — fin does not implement its own cryptography.
The local web server generates a self-signed RSA-2048 certificate with SHA-256 signatures via the cryptography library. SANs include localhost, 127.0.0.1, and ::1. Certificate validity is 825 days (browser maximum). TLS is required for non-loopback binding — if you expose fin on your LAN, it will refuse to start without a valid certificate.
On startup, fin checks whether full-disk encryption is enabled: fdesetup status on macOS, manage-bde -status on Windows. If FDE is off, fin blocks startup with setup instructions. This can be overridden with --i-understand-no-fde, but you have to mean it.
| Layer | Implementation |
|---|---|
| Rate limiting | slowapi token bucket — 200/min API default, 60/min drilldown/search, 10/min sync |
| CSP | default-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self' |
| Frame protection | X-Frame-Options: DENY |
| MIME sniffing | X-Content-Type-Options: nosniff |
| SQL injection | 100% parameterized queries (? placeholders). Zero string concatenation. |
| CSV formula injection | All exports sanitized — leading = + - @ \t \r prefixed with apostrophe |
| Upload limits | 5 MB hard cap with overshoot detection. Returns 413 if exceeded. |
HTTPS-only — rejects non-https:// URLs at validation time. Authentication via HTTP Basic Auth (RFC 7617). Credentials are extracted from the URL and sent as a header; only the hostname is ever logged. Retry logic via tenacity: 3 attempts, exponential backoff 2–10s, retries on transport errors only (not HTTP status codes).
Database files: chmod 0600 on Unix, icacls user-only ACLs on Windows. Data directories: chmod 0700 / restricted ACLs. Best-effort on creation — non-fatal if the OS rejects the call.
Transaction fingerprinting uses SHA-256 over normalized fields — no raw sensitive data in hash output. Amount parsing uses Python's Decimal type with ROUND_HALF_UP (standard financial rounding, not banker's rounding). Amounts exceeding $1M are rejected as a sanity check.
Every HTTP request is logged with client IP, method, path, status code, and response time in milliseconds. Static asset requests are excluded. SimpleFIN access URLs containing auth tokens are never exposed in error responses.
The source is the spec. If any of the above doesn't match what you see in the code, open an issue.
Requires Python 3.12+.
# Install from PyPI pip install getfin # Start the dashboard fin web # Opens http://127.0.0.1:8000/dashboard
Or install from source:
git clone https://github.com/arclighteng/fin.git cd fin python -m venv .venv source .venv/bin/activate # .venv\Scripts\activate on Windows pip install -e . fin web
Docker:
docker compose build docker compose run --rm fin sync docker compose run --rm fin web
CSV import — download a transaction export from your bank and drag it onto the import page. Format detection is automatic for major banks.
SimpleFIN — automatic daily sync. Subscribe at SimpleFIN Bridge (~$1.50/month), link your bank, paste the setup token into fin.
| Command | Description |
|---|---|
fin sync | Pull latest transactions from bank |
fin web | Start the web dashboard |
fin status | Financial summary at a glance |
fin trend | Monthly trend over time |
fin drill recurring | All recurring expenses |
fin drill one-offs | Discretionary spending |
fin drill alerts | Unusual charges with details |
fin audit-subs | Verify subscription detection accuracy |
fin bundle-check | Find overlapping subscriptions |
fin export-backup -p | Encrypted backup with passphrase |
fin export-csv | Export all data to CSV |
fin credentials set | Store credentials in system keyring |
| Flag | Window | Use case |
|---|---|---|
--quick | 14 days | Daily sync |
| (default) | 30 days | Weekly sync, covers statement cycle |
--full | 120 days | After a gap or absence |
--annual-bootstrap | 400 days | Initial setup, finds yearly subscriptions |
| OS | Database location |
|---|---|
| Windows | %APPDATA%\fin\fin.db |
| macOS / Linux | ~/.local/share/fin/fin.db |
Override with FIN_DB_PATH environment variable.
Enable full-disk encryption (BitLocker, FileVault, LUKS) for at-rest protection with zero fin configuration.
150+ services recognized on first charge. A sample:
Unknown merchants detected automatically after 3+ recurring charges with consistent amounts and regular intervals.