Skip to content

Security: CrossStar/sub2api-dashboard

Security

docs/security.md

Security

Trust model

The browser is untrusted, upstream responses are untrusted, and request headers are untrusted. Secrets remain server-side. This dashboard is read-only by design and deliberately does not expose a generic upstream proxy.

Secret handling

  • SUB2API_ADMIN_API_KEY is used only for group-filtered account pagination and account passive usage, in an x-api-key header.
  • User access, refresh, and temporary 2FA tokens are held in a dedicated encrypted Redis vault backed by a persistent AOF volume. Authenticated sessions survive browser close and dashboard restart; they expire after 7 days idle or 30 days absolute. Anonymous/2FA bootstrap state remains in a browser-session cookie with a 10-minute lifetime.
  • Browser cookies contain only an AES-256-GCM-encrypted opaque session ID. The session cookie key is separate from the Redis vault keyring; never reuse either with CSRF or account-reference keys.
  • Redis records and AOF files contain sensitive AES-256-GCM ciphertext. Protect the Redis volume and vault keyring, and retain old vault keys until sessions encrypted with them expire. Redis outages fail closed with HTTP 503 without clearing the browser cookie.
  • Losing the Redis volume or vault keys, absolute expiry, logout, or upstream invalidation requires login. The initial migration requires one login.
  • CSRF tokens stay in Pinia memory and POST requests require the session, exact PUBLIC_ORIGIN, acceptable Sec-Fetch-Site, and a valid HMAC token.
  • Account references and labels are pseudonymous HMAC-derived values scoped to their group.

Generate the cryptographic keys independently. Do not reuse a key between cookie encryption, vault encryption, CSRF, and account references. Do not commit .env or compose interpolation values. Rotate all affected keys and the upstream admin key after suspected disclosure; cookie-key rotation invalidates sessions and account-ref-key rotation changes displayed account aliases.

Authorization

The deployment allowlist is not sufficient by itself. Every group request must also be authorized by the current user's upstream available-groups response. Missing, malformed, unavailable, or failing authorization information denies access and prevents admin calls.

The upstream admin key must have the minimum permissions supported by upstream. Complete upstream bootstrap/setup and admin-key configuration there; this application never creates an upstream administrator or bypasses compliance.

Response and logging safety

Browser-facing DTOs are explicit allowlists. Do not add passthrough behavior to BFF schemas. Raw account rows are normalized before caching: retain only approved identity/classification fields, normalized top-level quota_* windows, and the approved Codex 5-hour/7-day fields extracted from extra. Never retain, log, or return full extra, credentials, emails, proxies, costs, internal metadata, or upstream bodies.

The server generates request IDs rather than trusting caller-provided x-request-id; this avoids header-controlled poison values entering DTOs or logs. User-facing unexpected failures use generic messages. Upstream HTML, malformed JSON, oversized bodies, timeouts, redirects, and non-success responses are normalized.

Network and container hardening

Terminate TLS at a trusted reverse proxy, set PUBLIC_ORIGIN exactly, enable COOKIE_SECURE=true, and configure TRUST_PROXY only for the proxy path you operate. Restrict outbound traffic to the configured upstream when infrastructure permits.

The example compose service runs non-root, read-only, with a small /tmp tmpfs, all Linux capabilities dropped, and no-new-privileges. Keep secrets in a deployment secret manager or an uncommitted environment source. Do not bake them into images.

Operational limitations

All caches, single-flight coordination, and rate-limit state remain process-local. Use one replica only; horizontal scaling remains unsupported until those states move to shared storage. A dashboard restart preserves authenticated sessions only when Redis and its keys remain available. Protect the persistent Redis/AOF volume and vault keyring as sensitive deployment secrets.

There aren't any published security advisories