Security overview
Last updated: May 19, 2026
Flush handles your bank connections, transactions, and financial decisions. Security is a first-order design principle, not a feature we bolt on. This page explains, honestly, what we do — and what we don't.
Flush is operated by Halo, LLC, a Wisconsin limited liability company.
1. Authentication
Flush does not store user passwords. We support two ways to sign in:
- Email magic link. A one-time link or 6-digit code sent to your email. Codes expire after a short window.
- Google OAuth. Authentication delegated to Google. We receive only your Google email, never your password.
Sessions are managed by Supabase Auth using short-lived JWTs and refresh tokens stored in your browser's local storage. Tokens are bound to your user identity and validated on every API call.
2. Data isolation — Row-Level Security
Every table in our database has Postgres Row-Level Security (RLS) enabled.
Every row is tagged with the owning user's ID, and every database policy requires that
auth.uid() match the row's user_id for the row to be visible or
modifiable.
This means data isolation is enforced at the database layer, not just in application code. Even if a bug in our API tried to query another user's records, the database would return zero rows. There is no "all users" view that the application can accidentally select from.
3. Bank connections (Plaid)
Your bank password never touches Flush. The credentials you enter to authorize a connection are entered into Plaid's interface, hosted by Plaid, and transmitted directly to your financial institution.
The long-lived access token never reaches your browser. It exists only inside our server-side functions and a database table with no client-readable policies.
The flow:
- You click "Connect a bank." Our server creates a short-lived Plaid link token tied to your user ID.
- Your browser opens Plaid Link with that token. You authenticate with your institution inside Plaid's interface. We never see those credentials.
- Plaid Link returns a short-lived public token to your browser, which our server immediately exchanges for a long-lived access token.
- The access token is written to a database table (
plaid_items) whose RLS policies do not permit any client (signed-in or otherwise) to read or modify it. Only our server-side functions, using a service-role credential, can use it. - Server-side functions use the access token to fetch your accounts and transactions, which are written to RLS-scoped tables that you can read.
You can disconnect a linked institution at any time from the Connections page. We immediately stop fetching new data and remove the access token on our side; you can also revoke Flush's access directly from my.plaid.com.
4. Payments (Stripe)
Subscription billing and invoice payments are processed by Stripe. We use Stripe Elements (or Stripe Checkout) for all card and bank-account entry; sensitive payment information is transmitted directly from your browser to Stripe over TLS and never reaches our servers. We store only a Stripe customer identifier and subscription status.
Stripe is PCI-DSS Level 1 certified. Their security practices are documented at stripe.com/docs/security.
5. Encryption
- In transit. All traffic between your browser, our application, and our infrastructure providers uses TLS 1.2 or higher.
- At rest. Database storage and backups are encrypted at rest by our infrastructure providers using AES-256.
- Secrets. API keys (Plaid, Stripe, Anthropic, Resend, etc.) are stored as encrypted environment variables on our Edge Function runtime, not in source code or client bundles.
6. Infrastructure
| Provider | Role |
|---|---|
| Supabase | Postgres database, authentication, Edge Functions, file storage |
| Vercel | Application hosting and content delivery |
| Plaid | Bank account connectivity |
| Stripe | Payment processing |
| Resend | Transactional email delivery |
| Anthropic | AI features (Claude API) |
Our infrastructure providers are widely used by financial software companies and maintain independent security certifications (SOC 2, PCI-DSS, and equivalent) appropriate to their role. We do not host any production infrastructure on our own machines.
7. Access controls
- Production access is limited to authorized personnel only and requires multi-factor authentication.
- Production database queries go through audited tooling; ad-hoc access is restricted.
- Our application code is reviewed before deployment.
- API keys and secrets are rotated when staff or scope changes warrant it, and at minimum annually.
8. Application security
- Input is validated server-side; we do not trust client-supplied user IDs.
- Authentication tokens (JWTs) are verified on every privileged operation; the user ID used for authorization comes from the verified token, never from the request body.
- Cross-Origin Resource Sharing (CORS) is configured per endpoint.
- Dependencies are kept current; we monitor for known vulnerabilities.
- Plaid and Stripe webhooks are verified using signed payload signatures before being processed.
9. Logging and monitoring
We log application errors, authentication events, and webhook activity. Logs are retained for an appropriate period to support debugging and incident response. We do not log bank account credentials, payment card numbers, or full access tokens.
10. Backups and disaster recovery
Our database is backed up continuously by our infrastructure provider with point-in-time recovery. Backups are encrypted and stored in geographically separate regions. We regularly verify that recovery from backup works.
11. Incident response
If we discover a security incident that affects user data, we will:
- Investigate scope and impact
- Take steps to contain and remediate
- Notify affected users without undue delay and, where required, within 72 hours of confirmation
- Notify regulators where required by applicable law
- Publish a post-incident summary when appropriate
12. Responsible disclosure
If you find a security vulnerability in Flush, please report it to jason@halo.ceo. We commit to:
- Acknowledging your report within 3 business days
- Investigating and providing a status update within 14 days
- Not pursuing legal action against good-faith researchers who follow this policy
- Crediting reporters (if desired) in our security advisories
Please give us a reasonable amount of time to remediate before public disclosure. Do not access, modify, or delete data belonging to other users in the course of testing.
13. Compliance posture
Flush is an early-stage product. We rely on the SOC 2-compliant infrastructure of our providers (Supabase, Vercel, Stripe, Plaid) and follow security best practices in the application layer above them. We are not yet independently SOC 2 certified. As Flush grows, we will pursue independent attestation appropriate to the customers we serve.
Privacy-related compliance (GDPR, CCPA) is described in our Privacy Policy.