Controls
56 controls across five areas. Each one says where it is verified, or what the gap is. Statuses are updated as the SOC 2 readiness work progresses and the change is noted on the Updates page.
In place running and verifiablePartial exists with a named gapPlanned on the readiness plan
Infrastructure security
Where the product runs, how it is reached, and how secrets are kept.
Production runs on audited cloud providers
Etropo manages no physical servers. The application runs on Vercel and the database, authentication and file storage run on Supabase (AWS). Both providers hold SOC 2 Type II reports.
Verified by: Provider SOC 2 reports, available from each provider’s trust page.
In placeDatabase and application hosted in the EU
The production database runs in AWS eu-central-1 (Frankfurt) and serverless functions execute in Vercel’s fra1 (Frankfurt) region. Static assets are served from Vercel’s global edge network. Some subprocessors, such as the AI model providers, process data in the USA. The Subprocessors page gives the region of each one.
Verified by: Database and function regions confirmed in the provider consoles, 2026.
In placeEncryption in transit
All traffic to app.etropo.com is served over HTTPS with TLS certificates issued and renewed automatically by Vercel. HTTP Strict Transport Security is set for two years and includes subdomains.
Verified by: Strict Transport Security header on every response, two years, subdomains included.
In placeEncryption at rest
Database volumes, file storage and backups are encrypted at rest by the provider (AES-256 on AWS).
Verified by: Supabase platform security documentation.
In placeIntegration credentials encrypted at the application level
OAuth access and refresh tokens for connected services (Google Ads, LinkedIn, Meta, TikTok, Google Sheets, Notion, HubSpot, Attio, Slack) are encrypted with AES-256-GCM before they are written to the database, with a per-record random IV and authentication tag.
Verified by: Application code review; the key exists only in the production environment.
In placeSecrets kept out of source control
API keys, the token-encryption key and database credentials live in Vercel environment variables. Production and preview environments use separate values. Nothing secret is committed to Git.
Verified by: Secrets held in the hosting provider’s encrypted settings; secret files are excluded from source control.
In placeNon-production deployments are access-protected
Preview deployments and raw deployment URLs require a Vercel team login. Only the production domain is public.
Verified by: Deployment protection confirmed in the hosting console, 2026.
In placeBrowser security headers
Every response carries a Content Security Policy, X-Frame-Options, X-Content-Type-Options and a Referrer-Policy, limiting script sources, framing and information leakage.
Verified by: Response headers checked on the production site.
In placeRate limiting on sensitive endpoints
Authentication, billing, AI, integration and mutation endpoints are rate-limited per user or IP with a sliding window in Upstash Redis. Clients receive 429 with retry information.
Verified by: Limits defined in application code and documented internally.
In placeBot protection on sign-in and sign-up
Sign-in and sign-up forms require a Cloudflare Turnstile challenge, verified server-side by Supabase Auth.
Verified by: Captcha enforced by the authentication provider for the whole project.
In placeMFA on production consoles
Access to Vercel, Supabase, GitHub and the domain registrar requires multi-factor authentication and an individual account. There are no shared logins.
Verified by: Information Security Policy §4. Attested by the account holder; not yet independently verified.
In placePlatform patching by providers
Operating systems, the PostgreSQL engine and the serverless runtime are patched by Vercel and Supabase. Etropo tracks major version upgrades (currently PostgreSQL 17, Node.js 24).
Verified by: Database and runtime versions confirmed in the provider consoles, 2026.
In place
Organisational security
The policies and people controls behind the product.
Information Security Policy maintained
A written Information Security Policy defines roles, data classification, access control, incident response and change management. It is reviewed at least annually and after major changes.
Verified by: Version 1.1 (May 2026). Public version in Resources.
In placeSupporting policies published
The policies behind the Information Security Policy, from access control to responsible disclosure, are published on this site.
Verified by: Resources → Policies, each with its version number.
In placeSecurity awareness training
Everyone with access to production systems completes security awareness training on joining and annually afterwards.
Verified by: Completed twice in 2025, most recently in November 2025; next round due November 2026. Completion records are kept internally.
In placeConfidentiality agreements
Personnel and contractors with access to customer data sign a confidentiality agreement before access is granted.
Status: Required by the Information Security Policy §11. The Confidentiality Agreement is published in Resources; signed records are planned.
PlannedAccess provisioning and removal checklist
Access to production systems is granted per role on joining and removed on the day of leaving, using a checklist that names every system.
Status: Access Control Policy §4. Checklist and records planned.
PlannedQuarterly access review
Every quarter the list of people with access to Vercel, Supabase, GitHub, Stripe and the other vendors is reviewed and any access no longer needed is removed.
Verified by: Access Control Policy §5. Last review completed in Q3 2026; next due by the end of Q4 2026. Review records are kept internally.
In placeEndpoint security
Laptops used for production access have full-disk encryption, lock within 15 minutes of inactivity, install updates automatically and run the built-in firewall. Customer data is not stored on personal devices; all access is through the browser.
Verified by: Checked on every laptop with production access when access is granted and at each quarterly access review; last checked in 2026. Device records and screenshots are kept internally.
In place
Product security
How the application itself keeps customers apart and keeps attackers out.
Tenant isolation enforced in the database
Every table in the application schema has PostgreSQL Row Level Security enabled. Policies tie each row to an organisation and check the caller’s membership, so an application bug cannot return another customer’s data.
Verified by: Checked against the production database in 2026: every table in the application schema has Row Level Security enabled.
In placeRole-based and category-level access
Each organisation has admin and user roles. Admins can further restrict users to specific budget categories; the restriction is evaluated in the database, not only in the interface.
Verified by: Access checks run in the database and are bound to the organisation; covered by automated tests.
In placeTwo-factor authentication
Users can enrol up to two TOTP authenticator devices. Once enrolled, every page, API route and database query requires a second-factor session: the proxy redirects, the API answers 403 and Row Level Security returns no rows until the second factor is verified.
Verified by: Enforced in three places: the page proxy, the API layer and the database’s row-level policies; covered by automated tests.
In placeGoogle sign-in
Users can sign in with a Google account instead of a password. Password sign-in uses Supabase Auth with bcrypt hashing, a 12-character minimum length, one-hour access tokens and rotating refresh tokens.
Verified by: Authentication provider configuration; sign-in page.
In placeSession lifetime limits
An idle browser is signed out after 15 minutes, and every session expires after 30 days at most.
Verified by: The application signs out a browser after 15 minutes without activity in any tab, after an on-screen warning. Authentication cookies are capped at a rolling 14 days, and an automated test fails the build if any client would issue a longer-lived cookie. The authentication provider expires every session after 30 days, or 7 days without use, and revokes a session when a refresh token is presented twice. Set in 2026.
In placeCompromised-password screening
New passwords are checked against known breach corpora (Have I Been Pwned) and rejected if they appear there.
Verified by: Enabled in the authentication provider in 2026.
In placeSign-up abuse controls
A database hook runs before any account is created and refuses disposable or blocked email domains on every sign-up path, including Google sign-in and invitations.
Verified by: A database hook that runs before every account is created, on every sign-up path.
In placeServer-side input validation
API routes validate request bodies with typed schemas before touching the database. Database access uses parameterised queries through the Supabase client; there is no string-built SQL from user input.
Verified by: Typed request schemas in the API layer; parameterised database client.
In placeWebhook signature verification
Inbound webhooks from Stripe, Slack, Microsoft Teams, Resend and Supabase are verified against their signing secrets before they are processed. Outbound cron jobs are authenticated with a secret.
Verified by: Signature check on every inbound webhook; a shared secret on every scheduled job.
In placeOAuth integrations follow the standard
Connections to Google, LinkedIn, Meta, TikTok, Notion, HubSpot, Attio and Slack use OAuth 2.0 with cryptographically random state parameters, minimum scopes, and tokens that customers can revoke from the integrations page at any time.
Verified by: Cryptographically random state values; connection code reviewed.
In placeAI features respect access control
AI Budget Buddy reads budget data through the same Row Level Security as the user, so it can only summarise what that user may see. Customer data is sent to model providers when a user asks a question or uploads a file, plus two scheduled Marketing Brain jobs for organisations with Budget Buddy enabled (line-item names daily, brain entries weekly), through API agreements that exclude training on customer data. Every call is traced to Braintrust; the “AI in Etropo” paper is available on request.
Verified by: AI tools read with the user’s own database permissions; an automated test fails if the chat assistants can read beyond the user’s access.
In placeDependency vulnerability monitoring
GitHub Dependabot alerts are enabled on the application repository and reviewed as part of regular dependency maintenance.
Verified by: Dependabot alerts enabled; no open alerts when last checked in 2026.
In placePenetration testing
An independent penetration test of the web application and API is performed at least annually, with findings tracked to remediation.
Verified by: Most recent independent test of the web application and API completed in October 2026 by Aikido Security. Etropo fixed 32 of the 35 findings and Aikido retested each fix. Etropo accepted the other 3 with a documented reason. The summary is published under Resources and the full report is shared on request; the next test is due by October 2027.
In placeVulnerability disclosure programme
Security researchers can report issues to security@etropo.com. Reports are acknowledged within 48 hours.
Verified by: Responsible Disclosure Policy in Resources.
In place
Internal security procedures
How changes ship, how incidents are handled, how the service recovers.
Change management through pull requests
Every change to the application is a Git commit on a branch, opened as a pull request, built as a preview deployment, and merged to main. Merging deploys to production atomically; the previous deployment can be restored in one click.
Verified by: Private source repository; production deploys only from that repository.
In placeAutomated checks on every pull request
Type checking, linting and the unit test suite (about 2,300 tests with coverage thresholds) run on every pull request; an integration suite runs against a confined test organisation. A change is merged only when every check passes.
Verified by: Continuous-integration workflows on every pull request, plus pre-commit and pre-push checks. The current GitHub plan cannot make the checks required, so the person who merges applies the rule.
In placeAutomated code review with human in the loop
An AI code review checks every change before merge, and a person approves every merge. Changes to sensitive areas also get a line-by-line human review.
Verified by: Every change goes through a pull request. CI runs type checks, lint, unit, DOM and integration tests, and an AI code review checks the branch before merge. A person reads every change to authentication, permissions, billing, data access, database migrations and the AI pipeline line by line, and approves every merge. Branch protection does not require a second reviewer.
In placeIncident response plan
A written plan defines four severity levels with response targets (P0 within 15 minutes, P1 within 1 hour), containment and recovery steps, and notice of a personal data breach to customers in time for their own 72-hour deadline.
Verified by: Security Incident Response Plan in Resources; Information Security Policy §9.
In placeIncident response plan exercised
The plan is walked through in a tabletop exercise at least once a year.
Status: First exercise scheduled before the SOC 2 observation period.
PlannedError and uptime monitoring with alerting
Application errors are captured by Sentry (EU data region) with alerts to the engineering Slack channel. Integration syncs, token operations and webhook deliveries are written to audit tables in the database.
Verified by: Error monitoring in the EU region with alerting; audit records in the database for syncs, token operations and webhooks.
In placeDaily database backups
Supabase takes automated daily backups of the production database, encrypted at rest. Restores are performed by the provider on request.
Verified by: Supabase backup schedule for the project. Point-in-time recovery is not enabled.
In placeBusiness continuity and disaster recovery plan
Recovery objectives are documented: application RTO 1 hour with instant rollback, database RTO 4 hours and RPO 24 hours from daily backups.
Verified by: Business Continuity and Disaster Recovery Plan in Resources.
In placeBackup restore tested
A restore from backup into a separate project is tested at least annually and the result recorded.
Verified by: Restore from backup into a separate project tested in 2025 and in 2026; results are recorded internally. The next test is due in 2027.
In placeLogs retained
Function logs are kept on Vercel for 30 days, and authentication and database logs on Supabase for 7 days. Integration, token-audit and webhook logs are kept in the application database and deleted automatically at the end of their retention period.
Verified by: Vercel Pro with Observability Plus (30 days of runtime logs) and Supabase Pro (7 days of log history). Token-audit logs are kept for 1 year, integration sync logs and webhook events for 90 days; a daily scheduled job deletes older rows (since 22 October 2026).
In placeAnnual risk assessment
Risks to customer data are identified, rated for likelihood and impact, and given an owner and treatment once a year and when the architecture changes.
Status: Risk Management Policy published. First assessment planned.
PlannedVendor review
Every vendor that processes customer data has a data processing agreement with Etropo and is reviewed for a current SOC 2 or ISO 27001 report before use and annually.
Verified by: The Subprocessors page lists each vendor with the data it receives and links its data processing agreement. Records of which DPA version applies to each vendor, and the date it was accepted, are being collected.
PartialCyber liability insurance
Etropo holds insurance that covers security incidents and their financial impact.
Status: Etropo does not hold cyber liability insurance yet.
Planned
Data and privacy
What is collected, how long it is kept, and how customers get it back or get rid of it.
Data classification
Data is classified as Highly Confidential (budget data, credentials, personal data), Confidential, Internal or Public, with handling rules for each.
Verified by: Information Security Policy §5; Data Management, Classification and Retention Policy.
In placeData minimisation
Sign-up asks only for name, email and password (or a Google account). Product analytics are sent server-side and contain user and organisation identifiers, not budget content.
Verified by: Sign-up form; server-side analytics events reviewed for content.
In placeSession replay in the application
Etropo records in-app sessions with Mixpanel Session Replay and a 10% sample with Sentry Replay to diagnose bugs. Both mask all page text and typed input, so a replay shows layout, clicks and navigation, not budget content. The one exception is the organisation-name field on the sign-up form, which stays visible so a replay shows which organisation signed up.
Verified by: Mixpanel configuration in the application (text and input masking on since 2026-10-22); Sentry masks text by default.
In placeCustomer data export
Customers can export any budget to XLSX from the budget editor, and sync budgets to Google Sheets or Notion, at any time without contacting support.
Verified by: Export dialog in the budget editor; Google Sheets and Notion integrations.
In placeDeletion on request
Account and organisation deletion requests sent to team@etropo.com are completed within 30 days. Deleted data persists in encrypted backups for up to 90 days after that.
Verified by: Privacy Policy (Data Retention) and the Data Management, Classification and Retention Policy.
In placeSelf-service account deletion
Users can delete their own account and organisation from inside the application.
Status: Not available in the product today; deletion is by request.
PlannedSubprocessor list published with change notice
Every vendor that processes customer data is listed on this site with its purpose, region and the data it receives. Changes are announced in the Updates feed before they take effect.
Verified by: Subprocessors and Updates pages, by email or RSS.
In placeData Processing Agreement
A standard DPA with the EU Standard Contractual Clauses, the technical and organisational measures and the subprocessor list as annexes, is published and applies to every customer. It takes effect with the Terms of Service; a countersigned copy is available on request.
Verified by: Resources → Data Processing Agreement (DPA), version 1.0, January 2026, with PDF download.
In placePrivacy policy and cookie consent
The privacy policy names the data collected, the legal basis, retention periods, third parties and the rights of data subjects. The marketing site asks for cookie consent before loading analytics.
Verified by: www.etropo.com/legal; cookie banner on the marketing site.
In placeNo card data stored
Payments are processed by Stripe Checkout and the Stripe billing portal. Etropo stores Stripe customer and subscription identifiers only.
Verified by: Stripe Checkout and billing portal; Stripe is PCI DSS Level 1.
In place