Unlevered handles sensitive tax data: client PII, income, financial documents, and IRC strategy outputs. This page describes the actual security controls in place, the standards they map to, and the parts of the system that are still maturing. We list what is built today, not aspirational language.
The Unlevered Tax Strategy Portal is a Next.js application hosted on Netlify with a Supabase Postgres backend. Application code, database, and storage are all isolated to a single Supabase project per environment. Every request flows through Netlify CDN to the Next.js runtime, which speaks to Supabase over TLS using either an anonymous key (with row-level security) or a service role key (server-side only, never exposed to the browser).
Production tenants are logically isolated by firm_id with row-level security policies on every tenant-scoped table. Database connections use the Supabase pooler with TLS enforced. Static assets are served from Netlify with HTTP/2 and modern TLS by default.
2.1 In transit. All connections to the portal use TLS 1.2 or higher, terminated at the Netlify edge with modern cipher suites. HSTS is enabled by default for the production domain. Supabase database connections from the Next.js runtime use TLS with certificate verification.
2.2 At rest (database). All Supabase Postgres data is encrypted at rest with AES-256, managed by Supabase using AWS KMS. This applies to every column, including the strategy database, client records, and audit logs.
2.3 At rest (object storage). Client document uploads (W-2s, 1099s, K-1s, prior returns) are stored in Supabase Storage with AES-256 server-side encryption. Files are never written to local disk on the application server.
2.4 Application-layer encryption. Sensitive fields that require additional protection beyond database-level encryption (MFA secrets, encrypted SSN fields, encrypted phone numbers) are encrypted in the application layer using AES-256-GCM with a unique 16-byte IV per record. The implementation follows NIST SP 800-38D for authenticated encryption. Encryption keys are loaded from environment variables and never committed to source.
2.5 Standards mapped. Encryption algorithms and modes used:
3.1 Identity provider. Authentication is handled by Supabase Auth, which provides email magic-link sign-in over PKCE for advisors and a separate client portal flow for end clients. Passwords, when used, are hashed with bcrypt by Supabase Auth (not stored in plaintext anywhere).
3.2 Multi-factor authentication. The portal supports TOTP-based MFA enrollment for advisors (compatible with Authy, 1Password, Google Authenticator, and any RFC 6238 compliant app). MFA secrets are encrypted at the application layer (see Section 2.4) before being stored. Advisors with the firm administrator role can require MFA for all team members.
3.3 Session management. Sessions are tracked in the portal_active_sessions table with device fingerprint, IP address, and last-seen timestamp. Administrators can revoke any session from the settings panel. Session cookies are HttpOnly, Secure, and SameSite=Lax.
3.4 IP allowlisting. Firms can restrict portal access to specific IP ranges via the portal_firm_ip_allowlist table. Administrators add CIDR blocks in settings; the middleware blocks requests from any IP outside the configured allowlist before routes execute.
3.5 Role-based access control. Each firm user is assigned one of five roles: admin, partner, senior_associate, associate, read_only. Role checks are enforced at the API and database level.
4.1 RLS on every tenant table. Every Postgres table that holds firm or client data has Row Level Security enabled with policies tying access to auth.uid() or the requesting firm ID. The current schema has 25 RLS policies across the portal tables, covering: clients, strategies, documents, messages, notifications, audit logs, deletion requests, export requests, and access grants.
4.2 Service role isolation. The Supabase service role key is used only on the server (Next.js API routes and server components) for operations that need to bypass RLS, such as cron jobs, webhook handlers, and trigger functions. The service role key is never sent to the browser and never bundled with client code.
4.3 SECURITY DEFINER functions. Database trigger functions (notifications, audit log writes) are defined with SECURITY DEFINER and a fixed search_path so they execute with elevated privileges only for their specific scope. They cannot be repurposed by an attacker to access other tables.
4.4 Tenant isolation enforcement. All API routes resolve the requesting firm ID from the authenticated session and pass it to Supabase queries explicitly. Any cross-tenant query is rejected by RLS even if the application code has a bug, providing defense in depth.
5.1 Encrypted file paths. The path to every uploaded document in Supabase Storage is encrypted with the same AES-256-GCM scheme used for sensitive fields. The plain filename is preserved for display, but the storage path is opaque.
5.2 Signed URLs for downloads.Documents are never served via public URLs. When an advisor or authorized client requests a document, the API issues a short-lived signed URL (default 60 seconds) bound to the requesting user's session. After expiration, the URL is unusable.
5.3 Malware scan status. Each uploaded file has a malware_scan_status column with values: pending, clean, infected, error. Files in pending or infected state are not downloadable. The pipeline for active scanning is in roadmap; today the column is plumbed and ready for an integration.
5.4 File type restrictions. Upload endpoints validate MIME type and file extension against an allowlist (PDF, JPG, PNG, DOCX, XLSX, CSV) and enforce a per-file size cap. Unrecognized types are rejected at the API boundary.
6.1 Audit log table. Every privileged action (login, document upload, document download, strategy approval, client deletion, data export, MFA enrollment, IP allowlist change) writes a row to portal_audit_log with: actor user ID, firm ID, action name, resource type and ID, source IP, user agent, and timestamp.
6.2 Tamper resistance. Audit log writes use SECURITY DEFINER functions so application code cannot delete or modify rows. Only the service role can purge logs, and only via documented retention jobs.
6.3 Right to deletion. Client deletion requests are tracked in portal_deletion_requests with status, reason, and a fulfillment certificate stored in portal_deletion_certificates. Deletions cascade through related records and write a final audit log entry.
6.4 Data export. Clients and firms can request a full data export via portal_data_export_requests. Exports are packaged as a single ZIP containing all client records, documents, messages, and audit log entries scoped to the requester, served via signed URL with a 24-hour expiration.
6.5 Retention. Client records and audit logs are retained for seven years from the last engagement, aligned with IRS recordkeeping guidance. After seven years, records are eligible for automatic purge unless under legal hold.
Unlevered is built to align with the following standards. We list them honestly: where we are aligned versus where we are formally certified.
8.1 Hosting. The portal runs on Netlify (application) and Supabase (database, storage, auth). Both providers maintain SOC 2 Type II compliance and operate from AWS US regions. Unlevered does not run its own server infrastructure.
8.2 DDoS protection.Inbound traffic is filtered by Netlify's edge network, which provides automatic DDoS mitigation, bot detection, and rate limiting on the CDN layer.
8.3 Secrets management. All API keys, encryption keys, and service credentials are stored as environment variables in Netlify and Supabase, never in source code. Rotation procedures are documented internally.
8.4 Dependency management. Application dependencies are pinned in package-lock.json. We use Dependabot and npm audit to surface vulnerabilities; security updates are applied within 7 days for high or critical CVEs.
9.1 Reporting a vulnerability. Security researchers and customers can report suspected vulnerabilities to support@unlevered.io. We aim to acknowledge within one business day and provide a status update within five business days.
9.2 Customer notification. In the event of a confirmed data breach affecting your firm, we will notify the firm administrator without unreasonable delay and provide the information required for the firm to meet its own notification obligations under applicable law and professional ethics rules.
9.3 Service availability. Status and incident history will be published at status.unlevered.io once the status page is live. Major incidents and post-mortems will be communicated by email.
Security on the Unlevered Platform is a shared responsibility between Unlevered and the advisor firm. We handle the controls listed above. You are responsible for the items below.
Items below are in active development and will be announced when shipped:
Security questions, vulnerability reports, or general support: support@unlevered.io
StayGuard LLC d/b/a Unlevered.io