What actually protects your data — stated plainly, including what we don't have yet. Last reviewed 2026-10-06.
Otto is a small, early product run by one person in the United States. It does not yet hold a SOC 2 report, an ISO 27001 certificate, or any other third-party attestation — and we won't imply otherwise anywhere. What it does have is a set of real, tested technical controls, listed below exactly as they exist, and a formal SOC 2 readiness program working toward an independent audit.
All traffic is encrypted in transit with TLS; the app sends HSTS with preload, so browsers refuse to speak plain HTTP to it. OAuth tokens and connected-account API keys are encrypted at rest with AES-256-GCM, and the decryption path fails closed: a value that isn't a valid ciphertext is refused, never used. Otto does not ask for the password to any other website and never uses one — it cannot sign in to a site on your behalf, so there is nothing it could do with one. A password saved by an earlier version of Otto stays encrypted and unused until you ask Otto to forget that saved login. Your own Otto password is never stored — only a bcrypt hash. Password-reset and email-verification tokens are stored only as SHA-256 hashes, expire quickly, and are single-use. The encryption key supports staged rotation without downtime.
Sessions live in an httpOnly, SameSite cookie that expires after 7 days without use; a session you keep using is renewed, so it does not run out on its own while you are active. You can see every signed-in device in Settings → Account and sign any one of them out. Changing or resetting your password invalidates every outstanding session immediately, and "sign out everywhere" does the same on demand — including paired browser-extension devices. Sign-in is protected by layered rate limits, a per-account lockout — five attempts in fifteen minutes, cleared the moment you sign in successfully or finish a password reset — and timing-equalized responses that don't reveal whether an email has an account. Every attempt spends one of the five, correct ones included, and that is deliberate: letting only wrong passwords count would have meant the lockout answered a question the rest of this paragraph is built to refuse, namely whether an address has an Otto account at all. A sign-in from a device Otto hasn't seen before triggers a notification email with the IP and device; a sign-in from a browser and network you have used before does not, so the alert that matters is not buried under alerts about yourself. If an account is suspended for misuse, every one of its sessions ends at once and the sign-in page says why.
Two-factor authentication is available on every account, using any standard authenticator app. With it on, a correct password is only half a sign-in: the server issues no session at all until the code is verified — the second step is enforced server-side, not a screen you can skip past. With it on, turning it off, making new recovery codes or deleting the account also needs a code from your authenticator or a recovery code, not just the password.
Getting an account at all is invite-only right now. An invite is a single-use link: the database stores only a SHA-256 hash of the token, the link expires in 7 days, both the page and its API are rate-limited per IP, and the invited person sets their own password — nobody hands one over, so no password ever travels through email or chat.
Anything Otto starts on its own — a routine, a message that arrived from someone else, or a turn in which it read words someone else wrote — cannot send, post or delete until you give an explicit yes. That gate is enforced server-side at a single chokepoint and fails closed. When you ask Otto yourself, in the app, to send or post something, the request is your go-ahead, with three brakes that stay on: an email is saved to your Gmail drafts unless you switch that setting off, a calendar invite to other people always waits for your tap, and a message to more than ten people always asks first. Requests are additionally checked for cross-site forgery at every authenticated gate, and every account's data is tenant-scoped: queries are structurally pinned to the signed-in user, and automated tests fail the build if a route forgets.
A dedicated, append-only security log records sign-ins and failed sign-ins, password changes, session revocations, data exports, account deletions, and administrative actions — with IP and browser info, retained for 400 days. Nothing in the codebase can edit a security-log row; an automated structural test enforces that only the retention sweep may remove them, and deleting your account removes the rows tied to it (the Privacy Policy, §7, names the one that stays).
The database is backed up automatically every night, and the newest seven copies are kept. The restore procedure is scripted and verifiable — the drill script rebuilds a scratch database from a backup and checks row counts and primary keys, not just "the file exists." Two limits on that are listed below. A health endpoint continuously reports database, scheduler, and backup freshness, and deployments fail closed: a migration error aborts the deploy and the previous version keeps serving. If our AI provider has an outage, Otto degrades honestly — a clearly-disclosed backup model with no ability to take real-world actions — rather than pretending nothing happened.
The test suite is in the hundreds of files and includes structural security guards: tests that read the source and fail if an API route lacks an auth gate, if an API route builds a database query from a raw string instead of bound parameters, if a secret-shaped string could reach logs, or if the account-deletion path misses a table that holds user data. Dependency vulnerabilities are gated: the gate fails on any high or critical advisory that is neither fixed nor covered by a written, owner-signed risk acceptance naming that specific advisory and an expiry date — a waiver never stretches to cover an advisory it doesn't name, so silent snoozing isn't possible. The gate is a check we run, not a clean bill of health, and it is failing today; what is outstanding is listed below rather than left for you to assume. Production secrets live only in the deployment platform's environment — never in a committed file, a script, or a chat — and log output is scrubbed against secret-shaped strings as a backstop; the one standing exception is named below too.
The complete list of sub-processors — every company that touches your data and what each one does — is published in the Privacy Policy (§5.7), along with what happens to your content when it's sent to an AI model and the routing restriction that keeps OpenRouter requests away from model providers that collect user data.
If you believe you've found a security issue, email team.ottohq@gmail.com with what you found and how. Reports go directly to the people who build Otto. Please give us a reasonable window to fix the issue before public disclosure; we'll tell you plainly what we found and what we did.