Security
PayStub stores your company's financial and PII data. This page documents what we protect and how. We update it when we change something material.
Data we collect
- Company identity (legal name, EIN encrypted, addresses).
- Worker identity (legal name, home address, email, last-4 SSN — we never collect or store the full Social Security Number).
- Worker tax profiles (W-4 + DE-4), wage rate, deduction configuration.
- Optional bank info for direct-deposit slips (routing + account number, both encrypted at rest).
- Pay-run and paystub records for 7 years (IRS retention rule).
Encryption
AES-256-GCM at the column level for SSN-last-4, EIN, bank routing, bank account, MFA secrets, and recovery codes. The Additional Authenticated Data is bound to model:field:rowId so ciphertext is non-portable across rows. All data in transit is TLS 1.2+ (TLS 1.3 preferred). The database uses TLS-only connections.
Today the master key lives in a server env var. A KMS migration (AWS KMS envelope encryption) is on our roadmap before SOC 2.
Multi-tenant isolation
Every row carries a company_id. A Prisma client extension auto-injects the active tenant into every read and write — calls outside a tenant context throw and never return rows. We have an integration test that proves Tenant A queries return zero rows even when asked for Tenant B's row by id.
Authentication
- Email + password (argon2id, OWASP-recommended parameters).
- Google + Microsoft Entra OAuth.
- TOTP MFA with 10 single-use recovery codes (encrypted at rest).
- Per-account lockout after 5 failed logins (15-minute window).
- Per-IP rate limit on login + Turnstile on sign-up and password reset.
Step-up authentication
Sensitive actions (issuing payroll, editing bank info, changing MFA, requesting account deletion, changing the Owner) require recent re-authentication — within 30 minutes of activity. Otherwise the server returns a 401 step-up challenge.
Audit log
Every write on a whitelist of payroll-relevant entities — companies, members, workers, bank accounts, tax profiles, deductions, pay runs, paystubs — is logged with the before/after diff, the acting user, the IP, the user-agent, and the request id. Encrypted columns are redacted to "<encrypted>".
Backups + retention
- Daily automated DB backups + point-in-time recovery up to 7 days.
- Quarterly restore drill (documented in our internal runbooks).
- Payroll records retained 7 years (covers IRS + most-state floor); aggregate financial figures kept under a
redacted_atflag after account deletion.
Compliance roadmap
- SOC 2 Type I — targeted post-MVP.
- AWS KMS for column encryption — before SOC 2.
- Read-side PII access logging — with SOC 2 prep.
Reporting a vulnerability
Email [email protected] with details. We acknowledge within 1 business day and aim to resolve high-severity issues within 7 days. Coordinated disclosure: please give us 90 days before publishing.