Security
Security isn't a feature. It's the product.
Arden holds your transactions, balances, and bank connections. That's an enormous amount of trust to ask for. This page tells you exactly how we protect it — and where we're still improving. No marketing fluff. Updated April 2026.
Five principles. Held to in code.
How we think about protecting your data.
- 01
Collect the minimum. Keep it the shortest time.
We can't leak data we don't have. Plaid is optional. Logs are scrubbed of emails, currency, and tokens. Retention windows are written down — and enforced by code, not policy.
- 02
Encrypt everything in motion. Encrypt everything at rest.
TLS 1.3 (1.2 fallback) on every connection. AES-256 on the database, on backups, on Vercel build artifacts. Bcrypt on every password. No plaintext secrets in logs, exports, or repos.
- 03
Authorize every row, every time.
Multi-tenant data is the #1 risk for an app like ours. Every database mutation passes through an ownership predicate before it touches a row by ID. Schema enforcement is separate from permission enforcement — both must pass.
- 04
Rate-limit every authentication surface.
Signup, login, login-per-email, email verification, two-factor verification, Plaid token exchange, data export. Sliding-window limits in Postgres, generous for humans, brutal for bots.
- 05
Be honest about gaps.
Real security means writing down what you don't do yet. The "What we don't do yet" section below is the part we expect you to read most carefully.
On the security roadmap
What we're working toward next.
A short list, kept honest. If something here matters to you, tell us — it'll move up the priority list. The full SECURITY.md has the longer technical follow-ups.
Application-layer encryption of TOTP secrets
PlannedTwo-factor secrets are encrypted at rest by Neon. We're adding a second layer — KMS-backed envelope encryption inside the application — so a database-only exfiltration scenario can't bypass 2FA. The current posture is already strong; this raises the floor further.
WebAuthn / hardware key support
PlannedTOTP via authenticator app is supported today. We're adding WebAuthn (YubiKey, Touch ID, Face ID, Windows Hello) as an alternative second factor — phishing-resistant by design, no shared secret to lose.
Third-party penetration test
Longer termExternal adversarial testing is the gold standard for catching what internal review misses. We'll commission one once the user base and budget justify it. In the meantime, we run a bug bounty via the disclosure address below.
SOC 2 Type II audit
Longer termFormal compliance attestation is a multi-month, multi-thousand-dollar undertaking that primarily serves enterprise procurement teams. We'll pursue it when there's a customer who needs it. Until then, this page and our public SECURITY.md are the substantive answer.
What's actually in place
Ten layers. Each one specific.
The exact controls running in production right now. Updated each time the underlying code changes — not annually for compliance.
01
Transport
Every byte you exchange with Arden is over TLS.
- TLS
- TLS 1.3 with 1.2 fallback. HTTP auto-redirects to HTTPS via Vercel.
- CSP
- Content-Security-Policy with default-src 'self' and an explicit Plaid allowlist. Frame-ancestors 'none' (Arden cannot be iframed).
- Other headers
- X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy strict-origin-when-cross-origin, Cross-Origin-Opener-Policy same-origin, Permissions-Policy denying camera/mic/geolocation/payment APIs.
02
Storage
Your data is encrypted on disk by everyone who touches it.
- Database
- Neon Postgres. AES-256 encryption at rest. US region. Pooled connections over TLS.
- Application
- Hosted on Vercel (us-west-2). Build artifacts and environment variables encrypted at rest.
- Plaid tokens
- Stored server-side only. Never returned to the client. Explicitly redacted from data exports. Deleted immediately when you disconnect a bank.
- Backups
- Neon point-in-time restore retains 7 days by default. Backups inherit the same encryption-at-rest as the live database.
03
Authentication
Passwords, sessions, and the optional second factor.
- Passwords
- Bcrypt with cost 10 (industry standard). Plaintext passwords never written to disk or logs.
- Sessions
- Stateless JWT, signed with HS256, 30-day expiry. HttpOnly + Secure + SameSite=Lax cookies. Server-side AUTH_SECRET validated at boot — must be ≥32 characters or the process refuses to start.
- Email verification
- Required before any write actions. Verification tokens are short-lived (24 hours) and rate-limited (10 attempts per 15 min per IP).
- Two-factor (TOTP)
- Optional, opt-in from Settings. RFC 6238 standard. Compatible with Authy, Google Authenticator, 1Password, Bitwarden. 10 single-use recovery codes generated at enrollment, stored as bcrypt hashes. Login verification rate-limited to 5 attempts per 15 min per (IP × user).
- CSRF
- Next.js Server Actions enforce same-origin checks on every mutation. SameSite=Lax cookies as a second layer.
04
Authorization
Every database mutation checks ownership before touching a row.
- Pattern
- Multi-tenant data is the #1 risk for an app like Arden. Every server action calls an ownership predicate (userOwnsAccount, userOwnsCategory, userOwnsTrackingAccount, userOwnsCategoryGroup) before SQL runs.
- Validation
- Every server action runs Zod input validation at entry. Shape enforcement (Zod) and permission enforcement (ownership) are separate; both must pass.
- SQL
- Tagged-template queries via the postgres library. Every value auto-parameterized. Zero string concatenation into SQL anywhere in the codebase.
05
Plaid
Connecting a bank is optional. The token never leaves the server.
- Optional by design
- Every feature works without Plaid. CSV import is a first-class flow. We never require a bank login to use Arden.
- Credentials
- Plaid receives your bank login directly via Plaid Link. We never see your bank password. Plaid sends us a long-lived access token in exchange.
- Access tokens
- Stored server-side in plaid_items.access_token. Never returned to the client. Never logged. Explicitly redacted from GDPR data exports.
- Disconnect
- Removing a Plaid item issues an itemRemove call to Plaid AND hard-deletes the row in the same transaction. No 30-day "grace period" — gone immediately.
- Webhook auth
- Plaid webhooks verify a JWT signature against Plaid's rotating public keys before any sync logic runs.
06
Retention
How long we keep what we keep.
- Your data
- Until you delete your account. Cascading delete via ON DELETE CASCADE through every owned table — user record, transactions, budgets, accounts, holdings, milestones, recovery codes — in one transaction.
- Plaid tokens
- Deleted immediately on disconnect.
- Server logs
- 30 days (Vercel default). Scrubbed of emails, currency, JWTs, and Plaid tokens before write.
- Rate-limit attempts
- Cleaned daily. Anything older than 24 hours is dropped.
- Email-verification tokens
- Cleared 24 hours after issue or on use, whichever first.
- Import sessions
- Deleted after 90 days (filenames may contain PII).
- Used recovery codes
- Deleted 90 days after consumption (ops audit window). Unused codes kept until the user regenerates them.
07
Your rights
Your data is yours. We make it easy to leave.
- Full export
- One click from Settings → Privacy & Data Export. Downloads a complete JSON snapshot of every account, transaction, budget assignment, goal, investment holding, scheduled transaction, and metadata row scoped to your user.
- Transactions CSV
- Spreadsheet-friendly export with date, payee, amount, category, account. Opens in Excel, Numbers, or Google Sheets. No paywall, no email gate.
- Account deletion
- One button in Settings → Danger Zone. Cascades through every owned table in a single transaction (transactions, budgets, accounts, holdings, milestones, recovery codes), revokes all Plaid connections, and deletes the user record. No 30-day soft-delete; no recovery window.
- Excluded from exports
- Passwords (bcrypt hashes) and Plaid access tokens are deliberately excluded. They never leave the server in any form.
08
Privacy & telemetry
No third-party analytics on the pages where your money lives.
- In the app (app.ardenmoney.com)
- No Google Analytics, no Mixpanel, no Segment, no behavioral tracking pixels. Period. Sentry runs only on uncaught exceptions, with PII scrubbed before send.
- On the marketing site
- Plausible Analytics — cookieless, no personal identifiers, no cross-site tracking, country-level geolocation only. Aggregate pageview counts so we know which pages get traffic.
- Sentry scrubbing
- Before any error report leaves our servers, a scrubber strips email addresses, currency amounts, JWTs, and Plaid tokens from the payload. See instrumentation.ts.
09
Monitoring & response
How we keep the posture current — and what happens if something goes wrong.
- Patch SLA
- Critical CVEs in 7 days. High in 30. Medium in 90. Low at next dependency bump. Tracked via GitHub Dependabot; pnpm.overrides used to pin security-critical packages.
- MFA on admin tools
- Multi-factor authentication enforced on every SaaS that touches user data: Vercel, Neon, GitHub, Plaid, Resend, the domain registrar.
- Incident response
- In the event of a confirmed security incident affecting user data, we will notify affected users within 72 hours with a clear description of what happened, what data was involved, and what we are doing about it. No legalese; no spin.
- Vulnerability reports
- Email security@ardenmoney.com. 72-hour acknowledgement target, 90-day coordinated disclosure window. Public credit on resolution unless you prefer anonymity.
Found something? Tell us.
We follow coordinated disclosure: 72-hour acknowledgement target, 90-day fix window, public credit when the fix ships (unless you want anonymity). Please don't run automated scanners against production — email first and we'll set you up with a sandbox.