Skip to content

Security

Specifics, not badges. Everything below is a property of the system you can hold us to.

Credentials

  • Passwords are hashed with argon2id. A sign-in attempt for an address that does not exist still performs a full hash verification, so response time cannot be used to enumerate who has an account.
  • Session tokens are 256 bits of randomness. Only the SHA-256 is stored — a database dump yields no usable session.
  • API keys work the same way: hashed at rest, shown once at creation, never retrievable afterwards. There is no reveal endpoint, because one would make a compromised session a compromise of every key it can see.
  • An API key can never exceed its creator. Its scopes are intersected with that member's live permissions on every request, so a key issued by an admin who is later demoted loses the same power they did.

Tenant isolation

Every query against org-owned data filters on the organization id, and the active organization comes from the session rather than from anything in a request. There is deliberately no route shape that accepts an organization id, so there is no per-route check for anyone to forget.

A dedicated test suite asserts that acting as one organization cannot read or change another's data, including through ids it has somehow learned.

Authorization

Deny by default, enforced at startup. Every route must declare the permission it requires or explicitly declare itself public — a route that declares neither throws during registration and the process does not start. Forgetting to authorize an endpoint is a crash at boot rather than a hole in production.

Transport and sessions

  • HTTPS everywhere, with HSTS in production.
  • Session cookies are httpOnly, Secure, and SameSite=Lax. Every mutation additionally requires a custom header, which a cross-origin form or image cannot set.
  • Payment webhooks are HMAC-verified against the raw request body, with a bounded replay window.

What we do not log

Full email addresses are masked before they reach a log line. Authorization headers, cookies, API keys and payment signatures are redacted at the logger.

Outbound requests

Both the crawler and the webhook delivery path refuse private, loopback and link-local addresses, including the cloud metadata endpoint. An endpoint that fetches a caller-supplied URL is a server-side request forgery primitive without that control.

Reporting a vulnerability

Use the contact form in the interim. The operator should replace this with a dedicated security address and a disclosure policy before launch.

What we do not claim

No SOC 2 report, no ISO 27001 certificate, and no penetration test have been completed. Claiming otherwise would be straightforwardly false, and a security page that overstates is worse than none.