Specifics, not badges
Every statement on this page describes shipped code and cites the work that implemented it. What we have not done yet is listed too.
Encryption
Jira and GitLab tokens are encrypted at rest with AES-256-GCM, using a derived key per key id, and can be re-encrypted under a new key with a rotation command.
Implemented in #173, #142
Decrypted integration tokens are never returned to the browser.
Implemented in #141
Cloud refuses to start without an encryption key.
Implemented in #142, #149
Session, bearer and admin tokens are stored only as hashes and compared in constant time.
Implemented in #128, #130
Security headers on every response: Content-Security-Policy, HSTS and related headers.
Implemented in #145
Authentication
Passwords are hashed with bcrypt; logins for unknown usernames cost the same as real ones, so accounts cannot be enumerated by timing.
Implemented in #133, #135
Per-account login backoff, a limit on admin-token attempts, and a configurable per-IP rate limit.
Implemented in #134
Login sessions have a capped lifetime and rotate when roles change; changing or resetting a password retires older credentials.
Implemented in #132, #131
Optional HttpOnly session cookie with CSRF protection instead of a bearer header.
Implemented in #190
Cloud Email verification and password reset use single-use, hashed tokens.
Implemented in #199, #200
Cloud OIDC single sign-on with PKCE and safe account linking.
Implemented in #201
Authorisation and tenant isolation
An authorisation matrix test covers every API route.
Implemented in #126
Cloud Each organisation is an isolated tenant, enforced by an access policy and tested route by route and on WebSocket joins.
Implemented in #195, #196
WebSocket connections are checked against an origin allow-list, capped per IP and per account, size-limited and schema-validated.
Implemented in #115, #117, #118, #119
CORS is restricted to an explicit allow-list of origins.
Implemented in #146
Input and outbound requests
Request bodies and WebSocket messages are validated against schemas; malformed messages are rejected.
Implemented in #108, #114, #127
Outbound calls to Jira and GitLab go through an SSRF-safe fetch: DNS answers are pinned, cloud-metadata and link-local addresses are always blocked, and upstream errors are generic. Cloud also blocks private networks.
Implemented in #65, #136, #137, #138, #149
Imported ticket links are only stored and rendered when they are http(s).
Implemented in #139
Cloud Stripe webhooks are signature-verified and processed idempotently.
Implemented in #204
Build and supply chain
CodeQL, Dependabot, npm audit, gitleaks and Trivy image scanning run in CI.
Implemented in #69, #150
Containers run as an unprivileged user.
Implemented in #148
Where your data lives
Cloud Cloud’s email and payments are built on Postmark or Amazon SES and on Stripe.
Implemented in #198, #203
Not done yet
Not yet No independent penetration test has been completed yet. We will say so here when one has, with its date and scope.
Not yet No SOC 2 or ISO 27001 certification.
Not yet Cloud’s hosting region and backup schedule are not announced yet; both will be published before Cloud leaves early access.
Not yet The complete Cloud sub-processor list is published with the legal pages before launch. (WEB-09)
Not yet A formal vulnerability disclosure policy and security.txt are in progress. (OPS-08)
Not yet Multi-factor authentication and a customer-visible audit log are planned for Cloud, not built.
Reporting a vulnerability
Email security@two-weeks.dev with the details and how to reproduce them. Please give us a reasonable chance to fix the issue before disclosing it publicly.