What protects a tenant, stated plainly.
No certifications we do not hold, no adjectives standing in for controls. Here is what is enforced, where it is enforced, and what is missing.
Isolation is structural, not policed.
Every query on workspace-owned data carries the workspace id in its predicate. There is no unscoped access path to forget to use.
The failure mode this design removes is the ordinary one: a correct system where one new endpoint, written in a hurry, omits a WHERE clause. If the data layer will not answer a question that does not name a workspace, that endpoint does not compile into a leak — it does not compile.
Adversarial leak tests pin the property rather than trusting the convention, because a convention is only as good as the last person who read the file.
internal/tenancy · migrations/0002
The audit log is append-only in the database, not in the application.
A trigger raises on any update or delete. An application that decides not to rewrite history is a policy; a database that refuses to is a control.
This is the difference an auditor asks about and a vendor usually cannot answer. If the only thing preventing a retroactive edit is that no code path performs one, then a support script, a migration, or an operator with a console can perform one and the log will not know.
internal/tenancy · migrations/0002 audit_log_immutable()
Keys rotate without an outage. Sign-in is phishing-resistant.
Rotation that requires a maintenance window is rotation that does not happen.
- 01
Key ids with overlapping validity
Per-workspace API keys and webhook secrets carry a key id. During a rotation both are valid, so you cut over on your own schedule and revoke afterwards.internal/tenancy · internal/outbox/sign.go
- 02
Passkeys for members and for operators
WebAuthn with user verification and a discoverable credential required — not optional, because these tokens sit in front of a money flow. Discoverable login resolves the account from the credential, so nothing is typed and there is nothing to phish.internal/passkey
- 03
Authenticator two-factor, stored correctly
A TOTP secret cannot be hashed — verification recomputes codes from it — so member secrets are sealed with AES-256-GCM under a per-context subkey rather than stored in the clear. An accepted code's counter is written back, so a code cannot be replayed inside its window.internal/membertotp · internal/secretbox
- 04
Hash where we can, seal where we cannot
A password or a recovery code is hashed, because the platform only ever needs to answer “is this it?”. A secret the platform must read back is sealed instead, and stores predating that construction are being migrated onto it rather than left as they are.internal/secretbox
Nothing leaves through a URL you configured.
A webhook destination is attacker-influenced input by construction — it is a URL a tenant types, and the platform then fetches it from inside its own network.
The dispatcher runs an egress guard before the request rather than trusting the hostname, which is the only ordering that helps: a check performed after resolution, or on the string rather than the address, is the check that DNS rebinding is designed to walk through. Loopback and private destinations are permitted only in sandbox and end-to-end runs, and that relaxation is an explicit flag rather than an environment sniff.
internal/outbox/ssrf.go · internal/outbox/dispatcher.go
We are not a custodian, and the code refuses to become one.
No member funds. No private keys. No platform credential inside a tenant's payment rail.
Members pay you
internal/rails
Configuration refuses ours
internal/rails
Claims instruct, never move
internal/claims
Verification without documents.
The provider session runs against your account. What returns is a decision and a non-reversible handle.
The handle is enough to enforce one person, one position, and nothing more. It is not enough to reconstruct an identity, which is the point: the safest way to hold a passport scan is not to hold one, and a breach cannot disclose data that was never stored.
internal/verification
What we do not claim.
If you are filling in a vendor questionnaire, these are the rows we would fail. Better here than in month four.
See /contact#security
Send the questionnaire, or take a sandbox and look for yourself.
Both are fine. One of them is faster.