Security

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.