Security

Security at thelayer that matters

Argon2id hashing, authenticated field encryption, hardware passkeys, and audited access. The technical foundation behind your financial data.

Last reviewed · reviewed on material architecture changes and at minimum annually

Encryption at every layer

From password storage to data at rest, Convexity uses modern cryptographic primitives. No legacy algorithms, no compromises. The spec, by layer:

LayerMechanismParameters
Password storageArgon2idtime_cost=3 · memory_cost=64MB · OWASP-recommended, memory-hardened, GPU/ASIC-resistant
Sensitive DB fieldsAES-256-GCM (authenticated encryption)Per-deployment key derived from server-side secret. Legacy Fernet (AES-128) kept decrypt-only through the backup retention window
TransportTLS + HSTSAll API + WebSocket, TLS 1.2 minimum (TLS 1.3 preferred). HTTP permanently redirected. HSTS on convexityos.com (includeSubDomains) and atava.ai
Access tokensJWT, short-lived15-min expiry + DB-backed refresh tokens. Rotation on each refresh; replay revokes the whole family
ThrottlingTiered rate limitsAuth 5 / 5min · API 120 / min / IP · AI 30 / min
Legacy upgradeSilent bcryptArgon2idOn next successful login. No user action required

Your data is scrambled, coming and going

When we store your data, we scramble it. When it travels between your browser and our servers, we scramble it. Even our team can't read your password; we only check that yours matches. Six places it matters:

  1. 01

    Your password

    We never store your actual password. We store a one-way scrambled version that even we can't reverse, using a method specifically designed to be slow against attackers, even ones with fancy hardware.

  2. 02

    Sensitive fields in our database

    Things like your authenticator-app secret and your linked-account access are scrambled with a key only our servers know. A stolen database without our servers would be unreadable for these fields.

  3. 03

    Data on the wire

    Everything between your browser and our servers travels through an encrypted tunnel, the same kind your bank uses. We force this on every request. There's no insecure version to fall back to.

  4. 04

    Sign-ins expire fast

    Sign-ins last 15 minutes and renew quietly in the background while you use the app. If somebody steals an active sign-in token, the renewal mechanism notices and revokes every related session.

  5. 05

    Slow-motion against attackers

    We cap how many times anyone can try a sensitive action per minute. Brute-force attacks that would take seconds against an unprotected service take years against ours.

  6. 06

    Quietly upgrading

    The next time you sign in, if your password is stored using an older scrambling method, we silently upgrade it to the latest. You don't have to do anything.

Layered identity verification

Three independent authentication factors plus Google SSO. Each layer adds protection without adding friction.

Layer 1

Password + Argon2id

Memory-hardened hashing with OWASP parameters. Automatic upgrade from legacy bcrypt on login.

Layer 2

TOTP multi-factor

Time-based one-time passwords via pyotp. Works with Google Authenticator, Authy, 1Password, or any TOTP app.

Layer 3

WebAuthn passkeys

Phishing-resistant FIDO2 authentication using hardware security keys or platform biometrics. Disclosed as a complete factor: a passkey login is sufficient on its own and does not require TOTP after enrollment.

+ SSO

Google OAuth 2.0

CSRF-bound login flow. A signed state JWT is paired with an HttpOnly Secure SameSite=Lax nonce cookie; the callback rejects any state whose nonce does not match. Tokens never appear in the URL query string; they ride the URL fragment, which never reaches our access logs.

Session management

Database-backed sessions with automatic expiry. Revoke individual sessions or all active sessions from any device.

Hash-chained audit logs

Append-only JSONL audit trail covering 30+ security event types: logins, MFA changes, password resets, session revocations, account modifications, and every require_admin action. Each entry carries prev_hash + entry_hash (SHA-256); any edit, deletion, or insertion breaks the next entry's chain on the next verify_chain walk. Concurrent writes serialize via threading.Lock + fcntl.flock so cross-process appends do not race.

Sign-in

Multiple ways to prove it's really you

Pick how you want to sign in. Each option is independent; using a stronger one doesn't mean giving up the others. The strongest options resist phishing entirely.

Option 1

Password

The basics. Stored using a method designed to be slow for attackers and is automatically upgraded over time.

Option 2

Code from your phone

Optional six-digit code from an authenticator app like Google Authenticator, Authy, or 1Password, the same kind your bank or email provider uses.

Option 3

Hardware key or fingerprint

Optional. Use a YubiKey, Apple Touch ID, Windows Hello, or any modern device-built-in passkey. Resists phishing: you can't be tricked into entering it on a fake site. Once enrolled, signing in with a passkey is enough on its own; we don't also ask for your authenticator code, and we say so plainly.

+ Google

Sign in with Google

One-click sign-in if you'd rather not manage another password. Your Google account does the verification on our behalf. We protect the round-trip with a one-time nonce so somebody can't trick your browser into signing you into a different account.

You can sign out everywhere

From any device, you can sign out one specific session, or sign out everywhere at once. Useful if you lose a phone or use a public computer and forget.

A paper trail you can verify

Every important account event (sign-ins, password resets, multi-factor changes, session sign-outs, every administrative action) is permanently recorded. Each row links to the previous one with a cryptographic fingerprint, so we'd be able to detect if anyone went back and edited or deleted history. Records are kept for 90 days at the system level.

Your data, your control

Sensitive fields in our database are encrypted with AES-256-GCM using a per-deployment key. Encryption and decryption happen server-side. We never sell, share, or monetize your financial data.

Encryption at rest
Sensitive database fields (TOTP secrets, linked account tokens) are encrypted with AES-256-GCM authenticated encryption. Decryption requires the server-side deployment key.
No data selling
We never sell, share, or monetize your financial data. Your portfolio, watchlists, and analysis belong to you.
Data export
Export all your data at any time via the account settings API. GDPR Article 20 data portability endpoint returns your complete profile, portfolio, watchlists, and notes.
Account deletion
Full GDPR Article 17 erasure support. Request account deletion and all associated data is permanently removed, including audit logs, sessions, and encrypted fields. Upstream tokens (Plaid item access tokens) are also explicitly revoked at the vendor on deletion, not just dropped from our database.
Webhook integrity
Inbound webhooks from Plaid and Stripe are signature-verified at the edge before any handler runs. Replays, forged item IDs, and any unsigned POST that lands on a webhook URL are rejected at 401 before they reach business logic.
Error tracking
Sentry is used for error monitoring and performance tracing. PII is excluded from error reports and replays are masked.
Product analytics
Mixpanel runs inside the terminal: page views, feature events, and a profile carrying your account id, email, display name, username and plan tier. Session replays are masked before upload, with every text node redacted and media blocked. Identifiers live in local storage, not cookies, and Do Not Track is honored. No advertising cookies, no tracking pixels, no cross-site tracking, no fingerprinting, and no analytics of any kind on this marketing site.
Infrastructure
All traffic reverse-proxied behind Nginx. API keys stored as server-side environment variables, never in client code. SQL queries parameterized via SQLAlchemy ORM.
Privacy

Your data belongs to you

We don't sell it, share it, or run an advertising business behind the scenes. You can take it with you. You can also delete it: fully, not "from view."

Locked away
The most sensitive bits in our database (the secret behind your authenticator app, your linked-account access) are scrambled with a key only our servers know.
No data selling
We never sell, share, or monetize your financial data. Your portfolio, watchlists, and notes are yours, full stop. There is no advertising business hiding behind the product.
Take it with you
You can export everything we have on you (profile, portfolio, watchlists, notes) at any time, in a portable format. This is your right under European privacy law and we apply it to everyone.
Delete means delete
If you ask us to delete your account, we permanently remove your data, including the activity records and the scrambled fields. Not "soft delete." Not "we'll keep a copy for marketing." Gone. We also tell Plaid to revoke our access to your linked accounts at their end, not just delete the token from our database.
Real mail, not forged
When Plaid or Stripe send us a notification, we mathematically verify the signature on every message before we act on it. Forged or replayed messages get rejected at the front door, so an attacker can't fake a "your account is verified" or "this payment cleared" event.
What we measure
We use one analytics service, Mixpanel, to see which parts of the terminal people actually use. It gets your account id, email, name and plan, the pages you open, and what you click. It also records sessions, but every word on the screen is blanked out in your browser before the recording is sent, so we see where you clicked and never what you were looking at or typing. Our error monitor sees crash reports with your personal info stripped. No ad trackers, no tracking pixels, nothing following you around other websites, and no analytics at all on this marketing site.
Boring server hygiene
All the things you'd expect a careful service to do: traffic goes through a hardened front door, secret keys are kept on the server (not in your browser), and we use industry-standard tools to protect against the most common attack types.

Information security policy

How we classify information, who is responsible for what, and which controls apply to which data. Effective 2026-04-17. Next review 2027-04.

Control domains

DomainControl
EncryptionArgon2id for password hashing. AES-256-GCM for at-rest field encryption on restricted data. TLS 1.2 minimum (TLS 1.3 preferred) for all transport. Legacy Fernet (AES-128) kept decrypt-only through the backup retention window.
Access controlJWT-based session auth; tier-based RBAC enforced at middleware on every request. See access control policy below.
AuthenticationPassword + optional TOTP + optional WebAuthn for account holders. MFA available, not yet mandatory.
Logging & monitoringStructured JSON logs with request-ID propagation. Sentry error tracking with PII scrubbed at the SDK layer. Hash-chained append-only audit log (SHA-256 prev_hash + entry_hash) covering 30+ security-sensitive event types plus every require_admin action; verify_chain(date) walks daily files for tamper evidence.
Webhook integrityPlaid and Stripe webhooks signature-verified at the edge before any handler runs. Stripe events deduplicated via IntegrityError on BillingEvent.stripe_event_id; charge.refunded and charge.dispute.created handlers downgrade tier on chargeback.
Vulnerability managementPatching SLAs: Critical 72h, High 14d, Medium 30d, Low 90d. Continuous scanning via Dependabot, pip-audit, unattended-upgrades. Backend dependencies pinned to exact versions (122 packages locked via requirements.txt; direct deps with extras + floors live in requirements.in). Most recent internal review 2026-05-26: closed 22 findings (4 Criticals + 6 Highs + 12 Mediums) same day. Independent third-party penetration test scheduled before enterprise GA.
Data retentionSoft delete with 30-day recovery. Hard delete on request. Full policy: /privacy.
Third-party riskSubprocessors disclosed publicly on this page. New subprocessors disclosed before data is shared.

Policy details

Scope
Applies to every person, system, and data flow involved in operating Convexity. As a solo-founder company today, "every person" means one individual; any future contractor or employee is subject to this policy from day one.
Information classification
Restricted: authentication secrets (password hashes, TOTP secrets, WebAuthn credentials, session tokens, API keys), linked-account tokens (Plaid, Stripe). Confidential: PII (email, name), portfolio holdings, analyst notes, AI chat history. Internal: usage telemetry, application logs, error traces. Public: marketing copy, published documentation.
Roles and responsibilities
The founder holds every security role (information security officer, system administrator, incident responder). When the team grows, these responsibilities will be formally separated and the policy will be updated to reflect that.
Exceptions
Any deviation from this policy must be documented with rationale and a remediation timeline.
Review cadence
Reviewed on material architecture changes and at minimum annually. Next scheduled review: 2027-04. Effective 2026-04-17. Owner: Founder.
Policy

The rules we follow

We have a written policy that says how we handle different types of information, who's responsible for what, and how often we review. Switch to Technical view above for the full policy text.

What we protect
Your sign-in credentials, your linked-account access, and your personal info get the strongest protection. Your portfolio data and analysis get the next tier. Application logs are kept internal. Marketing pages are public.
Who's responsible
Right now, the founder. As Convexity is one person today, every security role is held by that one person. As we grow, the role will be formally split and this page will be updated.
How fast we patch
Critical security holes within 3 days. Serious ones within 2 weeks. Less serious ones within 30 to 90 days. We scan automatically every day for new ones.
Outside review
We did a top-to-bottom internal review in May 2026. We have an outside expert lined up to do an independent assessment before we sell to enterprise customers.
If you delete
If you ask to delete your account, we mark it deleted immediately and fully erase it after 30 days. You can ask for immediate hard-delete and we'll honor it. Full details on the privacy page.
Outside vendors
Any outside service that touches your data is listed below in the Vendors section. We tell you about new ones before they get access.

Effective 2026-04-17 · Reviewed at least annually

Architecture

Zero trust, scoped honestly

Every request is independently authenticated and authorized at middleware before any business logic runs. There is no "trusted internal network"; even our own services are verified the same way external ones are. Nine controls we actually enforce, then the ones we deliberately do not claim.

  1. C-01

    Short-lived access tokens

    JWT access tokens expire in 15 minutes. No long-lived trust: if the token is stolen, the window for use is bounded by that ceiling.

  2. C-02

    Authorization at middleware

    tier_gate enforces RBAC on every protected route. Unauthorized requests receive 403 before the handler runs; no implicit privilege from session state alone.

  3. C-03

    Refresh-token chain revocation

    Refresh tokens rotate on each use and carry an auth_chain_id. Replay of any token revokes the entire chain, past and future. A stolen refresh token does not survive the legitimate user's next refresh.

  4. C-04

    Logout = JTI denylist

    Logout writes the access JWT's jti to a Redis denylist for the remainder of its 15-minute lifetime. Closes the "active access token lingers after sign-out" gap.

  5. C-05

    Hash-chained audit log

    Every audit row carries prev_hash + entry_hash (SHA-256). Any in-place edit, deletion, or insertion breaks the next entry's prev_hash check at verify_chain time. Cross-process appends serialize via threading.Lock + fcntl.flock.

  6. C-06

    Step-up MFA on admin actions

    Triggering a production deploy from the admin UI requires a fresh TOTP code beyond the active session. Session compromise alone is not sufficient to push code.

  7. C-07

    No enumeration on the auth surface

    Login responses are timing-equalized: a dummy verify_password runs even when the user record does not exist, so response times cannot distinguish "no such email" from "wrong password." Waitlist signup returns the same generic response for new and duplicate emails.

  8. C-08

    Secrets isolated to root + systemd

    Production secrets load from a root-owned env file at unit start. They never transit between processes in plaintext and are not readable from the application user account.

  9. C-09

    Brute-force protection, two layers

    Application-layer rate limits on auth endpoints (5 / 5min). Host-layer fail2ban bans repeated SSH attempts with a journald-backed jail.

Trust model

We don't trust anyone, including ourselves

Many older systems had an "inside" and an "outside": the outside was checked carefully, but anything that got inside was trusted. We don't operate that way. Every action is checked, every time, regardless of where it came from. The big ideas, then a few smaller ones.

Big idea 1

Sign-ins expire fast, and notice theft

Each "I'm signed in" pass is good for 15 minutes. When your session renews, the renewal mechanism is designed to detect theft: if somebody steals your session and tries to keep it alive, the very next renewal trips an alarm that signs out every related session at once.

Big idea 2

Permission checks every time

Every request is independently checked against your account permissions before it does anything. We don't assume you're allowed to do something just because you were a moment ago, and we don't carry "trusted" status anywhere on our side.

Big idea 3

Even we get checked twice

If the founder logs into the admin tool and asks to deploy new code, the active session isn't enough; the system asks for a fresh six-digit code from the authenticator app. We don't get a backdoor either.

  • No enumeration. If you type a wrong email, we don't tell the attacker that. Bad password and missing account look identical, including the response time.
  • Secrets stay in one place. Our server's secret keys live in one carefully-locked spot, accessible only by the system service that needs them. They never get copied or sent across processes in cleartext.
  • Two layers of brute-force protection. If someone tries to guess your password, our app slows them down. If someone tries to break into our servers directly, our servers automatically block their internet address after a few failed tries.
  • The activity log can't be quietly edited. Each entry mathematically links to the one before it, so if anyone tampered with history we'd be able to detect it.
Policy

Access control policy

Access to systems and data follows the principle of least privilege. Permissions are tier-based, enforced in application middleware, and granted only when required to deliver a specific feature. Scope covers user access to the application and operator access to the underlying infrastructure.

User access

  • Authentication. Email + password (Argon2id hashed), optional TOTP, optional WebAuthn passkey.
  • Authorization. Tier-based RBAC (Free, Pro, Pro Plus) enforced at middleware. Each route declares a minimum tier; unauthorized requests receive 403 before the handler runs.
  • Least privilege. Users access only their own records. No user has administrative access to other users' data.

Operator access

Single operator today (founder). Server access via SSH key-based authentication only; password logins disabled at the sshd level. Production secrets live in a root-owned env file loaded by systemd. MFA is enforced on all operator-facing third-party accounts (domain registrar, DNS, email, GitHub, VPS vendor, cloud console). Triggering a production deploy from the in-app admin tool requires a fresh TOTP step-up beyond the active session; session compromise alone is not sufficient. Every require_admin action is audit-logged into the hash-chained log.

Access revocation

  • User de-activation. Automated via backend/app/security/offboarding.py: revokes all tokens, disables MFA, deletes passkeys, disconnects Plaid, clears passwords.
  • Operator de-provisioning. Not yet applicable (solo founder). If a contractor or employee is added, their access will be revoked within 24 hours of separation per the offboarding script.

Reviewed on material architecture changes and at minimum annually · Effective 2026-04-17

Access

Who can see what

As a rule, you can see your stuff and only your stuff. The team can't see your portfolio holdings while wandering through the database. And our servers themselves are reachable only by one person, only with a hardware key.

What you can see

  • Your account, your data. You can see your portfolio, your watchlists, your notes, and that's it. You cannot see other users' data.
  • Tier-based features. Some features are gated behind paid tiers (Free, Pro, Pro Plus). The check happens at the front door of every request.
  • No "admin" backdoor. No customer support agent or anyone else has a way to log in as you and act on your behalf.

What we can see

Right now, "we" is one person: the founder. Our servers are reachable only by SSH and only with a hardware key. Password sign-in is permanently disabled at the server level. Outside services we use (domain, email, GitHub, server provider) all require multi-factor authentication. Even pushing new code to production from the admin tool requires a fresh authenticator code beyond the normal sign-in.

If you leave

  • Account closure. One automated step revokes all your sessions, disables your two-factor, deletes your passkeys, disconnects your linked accounts, and erases your password.
  • If we hire. When we add anyone to the team, they go through the same offboarding within 24 hours of leaving.

Reviewed at minimum annually · Effective 2026-04-17

Security review

Two internal reviews complete in 2026. First-wave hardening shipped 2026-05-02 across the application + infrastructure layers. Second-wave deep-dive on the 10 highest-leverage threats closed 22 findings (4 Criticals + 6 Highs + 12 Mediums) on 2026-05-26, all in one calendar day. We don't claim a third-party penetration test; that's tracked separately and listed below.

LayerReviewedStatus
Application (first wave)Authentication coverage across every route, authorization on cross-resource queries, ownership scoping on portfolio-bearing endpoints, AI-tool surface, billing & subscription paths.Shipped 2026-05: authentication required at the route layer for every account-bearing endpoint, resource ownership predicates enforced at database layer.
Application (second wave)SSO + OAuth flow, webhook integrity (Plaid + Stripe), GDPR upstream-revocation completeness, refresh-token reuse, frontend HTML injection, admin action auditing.Shipped 2026-05-26: SSO tokens moved out of URL query (now URL fragment), OAuth login flow CSRF-bound via signed state JWT + HttpOnly nonce cookie, Plaid webhook signature verification, Plaid token revocation on GDPR delete, refresh-token chain revocation, react-markdown sanitization for AI narrative, html.escape on EOD HTML, admin actions routed through require_admin audit hook.
InfrastructureSSH configuration, secret storage, log retention, system account privileges, third-party agent configuration, reverse proxy, stale config drift.Hardening runbook executed 2026-05-02. Brute-force ban at SSH layer, hardened sshd (key-only, restricted user list, low MaxAuthTries), secrets loaded by systemd. Idle-in-transaction PG sessions terminated at 60s by default.
DependenciesContinuous software-composition analysis on backend (pip-audit) and frontend (Dependabot). Automatic OS package updates via unattended-upgrades.Findings prioritized and remediated per the vulnerability-management patch SLA above. Backend now version-locked: 122 packages pinned to exact versions in requirements.txt.
Audit-log integrityWhether an attacker (or an insider) could quietly edit, delete, or insert audit entries without leaving evidence.Audit log now hash-chained (SHA-256 prev_hash + entry_hash). Tamper evidence verifiable via verify_chain(date). External mirror destination supported (env-gated) but intentionally unset until vendor selection.
External pen testIndependent third-party penetration test against the production application and infrastructure.Scheduled before enterprise GA, per the vulnerability-management policy. Vendor selection in progress.

Internal review at minimum annually · Most recent 2026-05-26 · 22 findings closed same day · Material remediations in release notes

Review

How often we check ourselves

We did two top-to-bottom security reviews in May 2026: the first covered every place an attacker could try to get in, the second focused on the 10 highest-risk threats. The second review closed 22 separate findings on a single calendar day. We've also lined up an outside expert to do the same, independently, before we sell to enterprise customers.

The app itself
We checked every page and every API to make sure you can't see anyone else's data, even by guessing URLs or fiddling with parameters. We also re-checked the parts that talk to outside services (Plaid, Stripe, Google sign-in) to confirm that nothing forged could trick us into thinking it was real.
The servers
We hardened how we sign in to our own servers, locked down where the secret keys live, kept system records longer for forensic purposes, and turned off accounts and tools we didn't need. Our database also automatically kills long-idle connections so a stuck process can't quietly hog resources.
Outside code
We use a lot of open-source libraries. Every day, automated tools watch for security issues in those libraries and alert us to apply updates. We've also pinned every single library to a specific version so we know exactly what's running. Operating system updates apply themselves on a regular cadence.
The activity log
Every important action (yours or ours) is recorded, and the records mathematically link to each other. If anyone tampered with history, we'd be able to detect it. There's also a slot for sending a copy of the activity log to a separate, outside system in case our own servers were ever compromised; we'll wire that up when we pick a destination.
Outside expert
A third-party security firm, not us, will run a full penetration test before we open up to enterprise customers. We're picking the firm now.

Internal review at least annually · Most recent 2026-05-26 · 22 issues closed same day

What we don't do yet

Honesty about gaps matters more than marketing claims. Here's what we're building toward.

We don't have SOC 2 certification. Evaluation planned for 2026 concurrent with multi-seat launch, but no auditor engagement yet. Single-operator pre-launch SOC 2 is theater; we'll publish the audit report when it is real, not a logo. In the meantime we self-assess against the Trust Services Criteria in the open: the readiness board.
We don't run a formal bug-bounty program with a public scope document and managed disclosure platform, and paid bounties are coming soon (see Incidents) rather than live today. We already accept good-faith disclosures at [email protected] under the safe-harbor terms below, and we credit researchers who report real issues.
We don't store your brokerage credentials. Plaid handles authentication on our behalf using tokenized access; we hold an access token, not your bank password.
We don't have ISO 27001 certification.
We don't yet enforce CSP. We ship Content-Security-Policy-Report-Only globally as of 2026-05-26 plus X-Frame-Options: DENY, and we're monitoring violation reports for ~1 week before flipping to enforce.
We don't offer zero-knowledge encryption. The server can decrypt data to display portfolios and run AI analysis. Field-level encryption protects at rest, not from the application itself.
We don't yet mirror the audit log to immutable external storage. The hash chain is tamper-evident on disk; an external mirror destination is supported by the code (env-gated) but intentionally unset until we pick a target (BetterStack / Slack / Cloudflare R2 / GitHub attestations are all on the table).

What we don't do yet

Being honest about what we don't have is more useful than marketing claims about what we do. Here's what's missing, and what we're working toward.

We don't have a major industry security certification yet (SOC 2, ISO 27001). These take time and money, and going through the formal audit with one person on the team would be theater. We'll do it when we add staff and start selling to enterprise customers. Until then, you can see exactly where we stand on our SOC 2 readiness board.
We don't run a formal bug-bounty program through one of the big platforms yet, and paid rewards are coming soon rather than live today. We still accept reports directly and will credit you for a real find. See "Report a bug" below.
We never see or store your brokerage password. When you connect a brokerage account, that login happens directly with Plaid (a regulated financial service used by most fintech apps). We only get a token that lets us read your balances and positions.
We turned on one of the advanced browser-side defenses (Content Security Policy) in "report only" mode on 2026-05-26, meaning browsers tell us if something looks wrong but don't yet block it. After a week of clean reports we'll flip it to actually block.
Our servers can read your data when they need to display your portfolio or run AI analysis. We protect it at rest and in transit, but we cannot honestly say "even we can't read it"; that would require a different kind of design that doesn't support the features we offer.
The activity log we keep is locally tamper-evident, but we haven't yet mirrored it to a completely separate, outside system. We will when we pick a destination.

Subprocessors

Outside services we use

Third-party services that process data on our behalf.

Every modern app uses some outside services. These are ours: what they do for us, and what they see.

ServicePurposeData processed
AnthropicAI analysis (primary)Prompts containing market data, portfolio contextWhat you ask the AI, plus the relevant market and portfolio context
OpenAIAI analysis (fallback)Prompts containing market data, portfolio contextSame as above, only used when Anthropic is unavailable
Voyage AIEmbeddings for semantic searchText sent for embedding: filings, transcripts, news, your search queries and research content you write or upload (no account identifiers)The text we turn into search indexes, including what you search for and research you write, with nothing attached that identifies your account
PerplexityWeb search with citationsSearch query text (no account identifiers)Just the words you search for, with nothing attached that identifies your account
PlaidBrokerage account linkingOAuth tokens, account balances, positionsAn access token (not your password) plus your balances and holdings
StripePayments and subscription billingEmail, account ID and username, subscription and purchase records. Card data is collected on Stripe-hosted checkout and portal pages and never transits our servers.Your email and which plan you bought. Your card details go straight to Stripe and never touch our servers.
GoogleSign in with Google (OAuth)OAuth authentication requests; only for accounts that use Google sign-inThe sign-in handshake, and only if you choose to sign in with Google
E2BSandboxed compute for assistant-written analysisRows from the datasets an analysis reads, which can include holdings and tax-lot cost basis (no account identifiers). The sandbox has no network access and is destroyed when the run finishes.Just the numbers a custom analysis needs, which can include your holdings, with nothing attached that identifies your account. The sandbox cannot reach the internet and is thrown away afterwards.
Financial Modeling PrepMarket data feed (quotes, fundamentals, WebSocket)Ticker symbols (no user data)
CoinGeckoCrypto market data (quotes, market charts)Coin identifiers (no user data)
SentryError monitoringError stack traces, performance metrics (PII excluded)Technical details about errors and performance; your personal info is stripped before it's sent
MixpanelProduct analyticsPage views, feature events, account id, email, display name, username, plan tier, device metadata, masked session replays (text redacted, media blocked)Which pages and features you use, your email and name, your account id and plan, basic device details, and screen recordings with every piece of text blanked out
IntercomSupport messagingConversation content, email address if you provide one, IP address, browser metadataWhatever you write to us in the support chat, your email if you give it, and basic technical details about your browser
OVHInfrastructure (VPS, US region)All application data (sensitive fields encrypted at the application layer)
CloudflareDNS, CDNHTTP requests, IP addresses
Let's EncryptTLS certificatesDomain names only

Incidents & disclosure

Track record & working with researchers

We publish our security incident count, third-party audit cadence, and bug-bounty status publicly because they are the simplest trust signals a prospect can verify.

Three things we keep public so you can verify them yourself: incidents we have had to report, when an outside firm last audited us, and where our paid bug-bounty program stands.

0
User-facing security incidents

As of . Any future incident gets a public post-mortem within 14 days; the count on this page updates same day.

Q3 '26
First external audit, scheduled

No third-party security audit has been performed yet – we are pre-launch and a one-person operation. The plan is an external review concurrent with multi-seat rollout.

Coming soon
Bug bounty

A paid bug-bounty is on the roadmap. We already accept good-faith disclosures under safe-harbor terms and credit researchers who report real issues. Scope: production hosts, the web app, the API. Severity scoring follows CVSS 3.1.

Honest about what we are not: Convexity is not SOC 2 certified yet. The certification is on the roadmap concurrent with the multi-seat launch – single-operator pre-launch SOC 2 is theater. We will publish the audit report when it is real, not a logo. Where we stand against the criteria today is public:the readiness board.

SOC 2 readiness

Where Convexity stands against the SOC 2 Trust Services Criteria: a dated, self-assessed readiness board with receipts. Not certified, not claiming to be.

codefamilycontrolsin · part · openpoll
CC1Control environment4 · 1 · 3HOLD
CC2Communication6 · 2 · 1HOLD
CC3Risk assessment2 · 0 · 2OPEN
CC4Monitoring3 · 2 · 1HOLD
CC5Control activities2 · 1 · 0GO
CC6Logical access17 · 9 · 4HOLD
CC7System operations9 · 4 · 2HOLD
CC8Change management7 · 1 · 3HOLD
CC9Risk mitigation3 · 0 · 3OPEN
A1Availability5 · 3 · 2HOLD
C1Confidentiality3 · 2 · 0GO
PI1Processing integrity6 · 0 · 0GO
PPrivacy4 · 3 · 2HOLD
in place partial openGO nothing open · HOLD open items remain · OPEN half or more not started
in place
Implemented and evidenced in the codebase or the written program. Each row in the expanded board below names the mechanism.
partial
Built with known gaps, or written but not yet proven in operation. An auditor tests operation, so we count it honestly.
open
Not started. Mostly organizational paper: assessments, agreements, cadences. Named below where naming it is safe.

A self-assessment is not an audit. SOC 2 reports are issued by independent, licensed CPA firms after examining evidence; nothing on this page substitutes for that, and we will not pretend otherwise.

Certification status

The badge wall, without the badges.

Single-operator pre-launch SOC 2 is theater. We will publish the audit report when it is real, not a logo.

the house rule, stated under Incidents too

  1. SOC 2 Type I

    not engaged

    A licensed CPA firm examines whether the controls are designed correctly at a point in time.

    No auditor engaged. Planned concurrent with multi-seat launch; this board is the preparation.

  2. SOC 2 Type II

    not engaged

    The same controls, observed operating effectively over a 3 to 12 month window.

    Follows Type I. Nothing is in progress, and no page of ours should tell you otherwise.

  3. Data-aggregator security attestation

    in progress

    The security attestation required by our brokerage-data aggregator for production access.

    Program underway against all ten requirements; targeted completion Q4 2026.

  4. External penetration test

    scheduled

    Independent offensive testing of the web app and API by an outside firm.

    Scheduled before enterprise GA, after the current hardening pass lands.

The board, expanded

Receipts, family by family.

The controls behind the counts: the mechanism, not adjectives. The full checklist with evidence paths lives in the repo's compliance program; this is the public cut.

Identity and access

CC6 · 17 · 9 · 4
  • in place:Password hashing is Argon2id, memory-hard, with legacy hashes upgraded transparently at loginargon2id
  • in place:15-minute access tokens; refresh tokens rotate, and reuse of a revoked token revokes the whole session linerotate + revoke
  • in place:MFA: authenticator codes, hardware passkeys, and one-time recovery codestotp · webauthn
  • in place:Google sign-in with anti-forgery state binding on the callbackstate-bound oauth
  • in place:Admin is a deny-by-default allowlist; every admin access is written to the audit logallowlisted · audited
  • in place:Every owned-data query is scoped to the authenticated account; no client-supplied user idsrow-scoped

Open: MFA enforcement for credential-linked accounts (built, staged behind a flag) · HSTS preload.

Encryption and secrets

CC6 · C1
  • in place:Field-level encryption for aggregator tokens, brokerage keys, and MFA secrets, with key rotationfernet · multikey
  • in place:Secrets live in the environment only; the app refuses to boot on a weak or missing keyfail-closed boot
  • in place:TLS 1.2+ with HSTS; inbound webhooks are signature-verified before processingverified ingress
  • in place:Secret redaction in logs, error reports, and admin views; secret scanning on the repositoryredact · scan
  • in place:Encrypted nightly database backups shipped off the serveraes-256 · offsite

Open: content-security-policy moves from report-only to enforcing (disclosed under Gaps above).

Audit trail and monitoring

CC4 · CC7
  • in place:Append-only audit log, hash-chained so tampering is evident, covering 30+ security event typessha-256 chain
  • in place:Read access to sensitive routes leaves its own audit traildata-access log
  • in place:Error tracking on both tiers with secret and PII scrubbing before anything leaves the boxscrubbed telemetry
  • in place:Public status page plus deep health checks (database, cache, disk, memory, vendor keys)/status
  • in place:Every data pipeline writes a sync ledger row; failures alert the operator on a fixed cadencedata_sync_log

Open: external audit-log mirror (env-gated, destination pending) · on-call escalation formalization.

Change and availability

CC8 · A1
  • in place:Release gauntlet on every change: type gates, test suites, migration-chain verificationpre-ship gates
  • in place:Staged deploys behind health checks, atomic release switch, one-command rollbackatomic · reversible
  • in place:500+ automated tests; account-erasure logic has database-parity coveragetested
  • in place:Dependencies pinned exactly and monitored for advisorieslocked deps
  • in place:Separate staging environment with production-isolation guards at bootstaging · isolated

Open: hosted CI enforcement · restore drills on a logged cadence · documented RTO and RPO.

Privacy and data lifecycle

P · C1
  • in place:Erasure is registry-driven: a table holding user data that skips the registry fails the builderasure registry
  • in place:Full-account export endpoint, generated from the same registry, secrets redactedportable
  • in place:Deletion revokes aggregator access upstream, not just our copy of the tokenrevoked at source
  • in place:No tracking pixels, no advertising cookies, no cross-site tracking; the marketing site runs no analytics at all. The product uses one analytics vendor, disclosed in the privacy policy, with session replays masked in the browser before uploadnamed · masked
  • in place:30-day recoverable delete, or immediate hard erasure on requestsoft + hard

Open: outside-counsel review of the privacy policy · retention automation completion.

Governance

CC1 · CC3 · CC9
  • in place:Written information-security policy plus eight subordinate policies (access, auth, retention, vuln management, incident response, lifecycle)9 policies
  • in place:Incident-response policy with a public post-mortem practice; real dated post-mortems existpracticed
  • in place:MFA verified on every vendor account that touches the systemvendor mfa
  • in place:LLC entity; governing law and subprocessors stated publiclyon the record

Open: formal risk-assessment cadence · vendor data-processing agreements · evidence automation.

Method

How this page stays honest.

Counted, not vibes. The numbers come from the criteria-by-criteria checklist in the repo's compliance program. Every "in place" cites its mechanism; two people re-counting would land on the same board.

Dated, then replaced. The board carries its assessment date. When an auditor is engaged, the engagement is disclosed here, and the eventual report replaces the self-assessment entirely.

Gaps, curated. Process gaps are named in the open. Anything security-sensitive is tracked internally and disclosed after the fix ships, the same policy this page applies to incidents.

Diligence

Running vendor diligence on us?

Send the questionnaire. We will walk it through this board line by line and show the receipts behind any row, including the ones we marked against ourselves.

[email protected]

DisclosureReport a bug

Coordinated vulnerability disclosure

Found something that looks wrong?

48-hour acknowledgement. 72-hour status updates until resolution. Safe-harbor terms for good-faith research; a paid bounty is coming soon.

If you spot something that looks like a security problem (a strange error, a way to see information you shouldn't, anything that worries you), please email us. We'll respond within 48 hours, no matter who you are.

$ mail[email protected]
01Response time
Initial acknowledgement within 48 hours. Status updates every 72 hours until resolution.
We'll write back within 48 hours, and keep you updated every 3 days until it's fixed.
02Safe harbor
We will not pursue legal action against researchers who discover and report vulnerabilities in good faith, follow responsible disclosure practices, and avoid accessing or modifying other users' data.
If you find a bug honestly (meaning, you don't try to read or change anyone else's data, and you tell us directly instead of going public first), we will not come after you legally. Curiosity is welcome.
03In scope
Production hosts, the web app, the API. Out of scope: this marketing site and third-party integrations on the vendor side. Severity scoring follows CVSS 3.1; a paid bounty is coming soon.
The live app, the live website you sign in to, the API. Not in scope: this marketing page or bugs that live in services we use (Plaid, Stripe, Google). Paid rewards are coming soon; for now we credit researchers who report real issues.

Questions about our security architecture?

Questions about how we protect your information?

[email protected]