Sign in Get API keys
Reference · For security teams

Security

QuickZTNA's cryptographic commitments, threat model, authentication flows, and audit guarantees. This is the doc to hand to your security team or auditor — honest about what we defend against and what we don't.

Post-quantum cryptography

Hybrid by default, no toggle Every peer-to-peer tunnel — on every plan — uses X25519 + ML-KEM-768 hybrid key exchange. There is no configuration. Peers without PQC support gracefully fall back to classical-only WireGuard; mixed fleets work fine.

Each tunnel's PSK is derived from a combination of X25519 ECDH and ML-KEM-768 KEM shared secrets:

// ztna/client/pkg/crypto/pqc.go
PSK = HKDF-SHA256(
    secret: X25519_shared || ML-KEM_shared,
    salt:   nil,
    info:   "quickztna-pqc-wg-psk-v1",
    length: 32,
)

Implementation files:

  • ztna/client/pkg/crypto/pqc.go — keygen + encap/decap + PSK derivation (Go stdlib crypto/mlkem, no external library)
  • ztna/client/pkg/agent/pqc.go — per-peer state cache
  • ztna/client/pkg/wireguard/engine.go — PSK injection into WireGuard IPC
  • backend/src/handlers/key-exchange.ts — server-side relay
  • backend/migrations/043_pqc_key_exchange.sql — 4 nullable columns on key_exchanges

Control plane — TLS + JWT

  • TLS: Caddy auto-TLS via Let's Encrypt. HSTS preload, TLS 1.2+, modern cipher suite only.
  • JWT: ES256 (ECDSA P-256 + SHA-256). Issuer quickztna, audience quickztna-api. 1-hour access token, 30-day refresh token.
  • Refresh cookie: __Host-refresh_token — HttpOnly, Secure, SameSite=Strict, Path=/. The __Host- prefix pins the cookie to exact origin with no Domain attribute.
  • WebSocket auth: token via Sec-WebSocket-Protocol subprotocol header — never in URL. Prevents token leak to proxy logs, CDN caches, browser history.
  • DERP relays: TLS 1.3 minimum with X25519Kyber768 hybrid KEM enabled at the TLS layer.

At rest

  • PostgreSQL: disk encryption (Docker volume on encrypted host)
  • Secrets vault: AES-256-GCM. Per-org DEKs, sealed by master KEK in env
  • R2 object storage: server-side encryption (Cloudflare-managed keys)
  • Backups: daily pg_dump to R2, 7-day local retention, encrypted in transit and at rest

Password hashing

  • PBKDF2-SHA256, 100,000 iterations, 32-byte key, random salt per password
  • Legacy SHA-256 hashes auto-upgraded on successful login
  • Timing-safe verification: dummy PBKDF2 against a pre-computed hash for non-existent users — login timing is constant (anti-enumeration)

TOTP MFA

  • RFC 6238 compliant, 30-second window, ±1 step drift tolerance
  • Replay protection: used codes cached in KV for 90 seconds
  • Backup codes: 10 one-time codes, SHA-256 hashed at rest

Authentication model

User (dashboard)1h / 30d

Email+password → JWT pair; refresh via __Host- cookie

User (SSO)1h / 30d

SAML / OIDC → JWT pair. Same tokens as password login.

User (CLI)1h / 30d

Browser OAuth flow → one-time code → JWT pair

Agent (ztna)node_key

Auth key on first boot → permanent node_key. Auth key is revocable.

Service (SCIM, Terraform)API key

Long-lived until revoked. Org-scoped.

SuperadminJWT (hardcoded)

Platform operator only. Cannot bypass plan gates at backend.

Refresh token binding: refresh tokens are bound to a device fingerprint (UA + /24 IP prefix). Token theft across devices fails with DEVICE_MISMATCH.

Account lockout: 10 failed logins per email per 5 min → 15-minute lockout. Dummy PBKDF2 ensures lockout response is timing-identical to invalid-credentials response.

Token blacklist: password change and account deletion set jwt_blacklist:<user_id> in KV (TTL = 30d, matching refresh token). All existing tokens reject immediately.

CSRF protection

Origin check on every state-changing request. Only whitelisted origins (login.quickztna.com, dev hosts) accepted. Combined with CORS (only whitelisted origins in Access-Control-Allow-Origin), this is sufficient for a same-origin SPA. No X-CSRF-Token cookie — Origin check + HttpOnly cookies is the chosen model.

Rate limiting

/auth/loginper IP · per email

10 / 5 min · 10 / 5 min (separate counters)

/auth/signupper IP

5 / 5 min

/auth/reset-passwordper IP

5 / 5 min

/auth/mfa/*per user

5 / 5 min

/auth/change-passwordper user

5 / 5 min

WebSocket connectionsper org

200 concurrent

WebSocket broadcastper client

10 / min · 4 KB payload max

Client IP detection: cf-connecting-ipx-real-ipx-forwarded-for. x-forwarded-for is never trusted first (spoofable).

Secrets handling

  • Private keys (CAs, signing keys, WireGuard static keys) encrypted with AES-256-GCM before DB insertion. Fail hard if encryption fails — never fall back to plaintext
  • Environment: JWT_PRIVATE_KEY, JWT_PUBLIC_KEY, master KEKs live in Docker env vars (not in the image)
  • Rotation: secrets vault items support scheduled rotation via secret-rotation cron

Audit trail

Every state change writes to audit_logs with:

  • org_id, user_id, action, resource_type, resource_id
  • details (JSONB), ip_address, user_agent, created_at

Immutable — no UPDATE, no DELETE paths in application code. 90-day retention via audit-log-retention cron. Exported to Loki for cross-org observability.

Data handling

  • Org isolation: every DB query filters by org_id or fails. Enforced at middleware level; never trusted from client input
  • Cascade deletes: preserved where orphan rows are safe. SET NULL used for audit/compliance tables so records survive user deletion
  • GDPR: /auth/delete-account cascades user-scoped data; anonymizes audit rows; notifies via email
  • PII in logs: user-agent, IP, email truncated. Never passwords, keys, or tokens
  • Docker capabilities: firewall container has only NET_ADMIN + NET_RAW. SYS_ADMIN removed (it was equivalent to root)

Threat model

What we defend against

  • Passive network adversary — TLS + WireGuard PQC tunnel protects everything in transit
  • Future quantum adversary — ML-KEM-768 hybrid key exchange; stored traffic cannot be decrypted post-quantum
  • Credential theft — 1h access token + device-bound refresh + blacklist-on-change + MFA + posture
  • Server-side compromise of one org — org isolation means one tenant cannot reach another's data
  • Cross-site request forgery — Origin check + SameSite=Strict cookies
  • XSS token theft — access token in memory only (never localStorage); refresh token in HttpOnly cookie
  • Bruteforce — per-IP and per-email rate limits; account lockout; timing-safe password verification
  • Replay attacks — TOTP replay cache; refresh token single-use (rotates on each refresh)
  • Log injection — structured logs via pino; user input never concatenated into log lines

What we do NOT defend against

Honest limits These are out of scope for the current build. Important for your threat model.
  • Root-level compromise of the production server — would expose everything. Mitigation: UFW firewall, non-root container users, secrets in env only
  • Compromise of the CA signing key — used for issued x509/SSH certs. Mitigation: short-lived certs (≤ 1h), rotation
  • Malicious authorized admin — an org admin with legitimate credentials can exfiltrate their own org's data. Mitigation: audit logs, session recording
  • Supply-chain attacks on upstream Go/Node deps — Mitigation: lockfiles, Dependabot, minimal deps
  • Data residency — data currently lives on servers in the chosen region only. Multi-region replication available on request

Vulnerability disclosure

Security issues: email security@quickztna.com. PGP key on /.well-known/security.txt.

We commit to:

  • Acknowledging receipt within 24 hours
  • Triaging and providing status within 5 business days
  • Coordinated disclosure on a timeline appropriate to severity
  • Public credit in release notes (opt-out available)

Out-of-scope: rate limit abuse that doesn't exfiltrate data, missing best-practice headers on non-sensitive endpoints, self-XSS.

Compliance

Policies and readiness documents available on request to sales@quickztna.com:

  • SOC 2 readiness
  • Audit log policy (90-day retention, immutable, exportable)
  • Business continuity (daily backups, 25h staleness alerting, streaming replication)
  • Data handling policy (classification + retention)
  • Information security policy