Skip to content

Security: wellparth/ZeroTrust

Security

docs/security.md

Security

Zero Trust Guard's security model rests on a few deliberate choices. Reviewed together with docs/threat-model.md and the ADRs.

Core assumption

The gateway is the only way into a protected application. If a request does not carry a token the gateway can positively verify, it is rejected before the upstream server processes it. The upstream must also validate the x-ztg-* headers (see the demo upstream), because defense-in-depth means the gateway is trusted but not implicitly sufficient.

Authentication

  • Passwords are stored as scrypt hashes (utils.ts), verified at boot against configs/users.json; plaintext is never stored.
  • Login issues a short-lived access JWT (default 900s) and an opaque refresh token (default 7 days) with rotation — each refresh consumes the old refresh token.
  • The access token is HS256-signed with node:crypto (jwt.ts) using ZTG_JWT_SECRET.

Authorization

  • Every request is checked against the session and device server-side state, not just the token signature, so revocation is immediate.
  • The PolicyEngine decides authentication/device-verification requirements, required roles, explicit deny rules, and per-route rate limits.
  • Admin control-plane endpoints (/sessions /devices /routes /policies /metrics /audit/events) require the admin role.

Transport and headers

  • The gateway sets x-content-type-options: nosniff, x-frame-options: DENY, and referrer-policy: no-referrer.
  • It injects x-ztg-verified, x-ztg-user-id, and x-ztg-request-id only after the gate passes. Clients cannot forge these without passing the gate.

Fail-closed and availability

  • Fail-closed: an unavailable session store denies rather than accepts.
  • Fail-open only where it cannot create risk: audit persistence (Postgres) degrades to an NDJSON file sink so audit writes never block the request path.

Secrets

Secret Location Notes
ZTG_JWT_SECRET environment Change from the dev default
ZTG_ADMIN_TOKEN environment For gateway-level admin bootstrap
Postgres/Redis creds environment / compose Not committed

Never commit real secrets. Rotate ZTG_JWT_SECRET if compromised; all tokens become invalid, forcing re-login.

Rate limiting

  • Per-IP login attempts: 5/min (fail-closed).
  • Global per-IP request guard: 1000/min.
  • Per user+route policy limit (e.g. payments: 20/min).

Operational checklist

  1. Run in front of TLS (terminate at a reverse proxy or use an HTTPS listener).
  2. Keep ZTG_JWT_SECRET long, random, and rotated.
  3. Use the in-memory KV fallback for development and tests only; production needs Valkey/Redis.
  4. Confirm the network only permits traffic to upstreams from the gateway.
  5. Monitor /metrics and /audit/events for anomalies.

There aren't any published security advisories