Statement AI is live  ·  Reconciling Canadian PDFs to the cent

Security

Your statement is sensitive. We treat it that way.

The Balancely pipeline is deliberately boring: process in memory, persist as little as possible, hash everything that needs hashing, and keep the auditable surface tiny. Here's the concrete posture.

PDFs are never stored

Every uploaded PDF is processed in memory by the route handler and discarded the moment the workbook is built. We don't move files to object storage, we don't snapshot them in logs.

No per-transaction data lands in Postgres

Lean storage mode: only the audit summary (filename, document type, totals reconciled, parser confidence) lives in the database. Individual transactions stay client-side.

Passwords hashed with bcrypt

bcryptjs at 10 rounds. The plaintext password never leaves the request body — it's hashed before insert. We can't see your password and we can't recover it.

OTPs and reset tokens are hashed before storage

Verification codes (6-digit OTPs) and password-reset tokens are SHA-256 hashed in the database. A database read alone can't verify an account or reset a password.

Sessions: encrypted cookies, server-only

iron-session AES-256 encrypts the cookie with a 32+ char secret. HttpOnly and SameSite=lax. No session is stored server-side — the cookie itself is the session.

Single-use, short-lived tokens

OTPs expire after 10 minutes and self-invalidate after 5 wrong attempts. Reset links expire after 60 minutes and consume on first use. Issuing a new code invalidates the previous one.

Google sign-in: state is HMAC-signed

Our OAuth state parameter carries an HMAC-SHA256 signature with the session secret and a 10-minute TTL. Callbacks that don't verify are rejected before any token exchange.

No prompt-injection from PDFs

PDFs are sent to the parser as binary inlineData, never spliced into the system prompt. A malicious PDF can't talk to the model.

Common questions

The questions security teams ask.

Do you train AI on my statements?

No. Statements pass through Statement AI for parsing only; the file and its contents are not retained after the parse completes. Our processing agreement with the underlying model provider excludes your data from any training program.

Where are the servers?

Compute and database both run in the US East region for low parser-to-database latency. We can move regions for enterprise plans on request.

How do I delete my account?

The Danger Zone in /dashboard/settings will permanently remove your user row and all audit-log entries. The button is currently disabled while we finalize the account-deletion flow.

What happens if Statement AI hallucinates a transaction?

Reconciliation catches it. The reconciler sums the parsed transactions per bucket (payments, returns, charges, interest) and compares to the totals printed on the statement. Anything off by more than 2¢ flags the workbook as unreconciled.

Can I see what you log?

Server-side: filename, file size, parser used, parser confidence, reconciliation result, timestamps. No transaction descriptions or amounts. Logs go to Vercel and (optionally) Sentry — both private.

PIPEDA / Canadian privacy?

We process limited personal data (your email + a display name) under contract for the purpose of providing the service. No marketing email use, no third-party sale, no analytics on statement contents. Privacy contact: privacy@balancely.ca.

Report a security issue.

Email security@balancely.ca with reproduction steps. We respond within one business day for verified reports and credit researchers in release notes.

In scope

  • · Auth bypass, session fixation, OAuth state replay
  • · OTP / reset-token weaknesses
  • · SQL injection, server-side request forgery
  • · Privilege escalation between accounts
  • · Prompt-injection that leaks user data

Out of scope

  • · Self-XSS via paste / DevTools
  • · Findings on the marketing site without security impact
  • · Rate-limit reports on unauthenticated endpoints

Want the full privacy story? See our Privacy Policy and Terms.

Get started