Threat model & security controls
| Asset | Threat | Control |
|---|---|---|
| Kraken API keys | leak via chat/logs/git/browser | env-injected only (PM2 env from the gateway manifest, 0600); never returned by any endpoint; structlog redaction of key-like fields; .env git-ignored; separate data/trade keys; withdrawal permission never requested; preflight warns if the data key can trade |
| Owner session | brute force, CSRF, XSS | bcrypt (cost 12) owner password; signed HttpOnly SameSite=Lax cookie (Secure in prod); login rate limit 8/min/IP; mutations require same-origin Origin/Referer; X-Content-Type-Options, Referrer-Policy; no secrets in localStorage |
| Order flow | strategy/agent bypassing limits | every order (backtest/paper/live) goes through RiskGateway (pure, default-deny); kill switch in DB + Redis; live adapter behind feature flag + UI double confirmation (Phase 5) |
| Data integrity | corrupted book / stale feed | CRC32 checksum on every book update, resubscribe on mismatch; staleness and clock-drift checks in the gateway; gaps recorded, never silently filled |
| Audit | tampering with history | append-only audit_log with SHA-256 hash chain; /api/audit and ktrade audit-verify verify the chain |
| Network | exposure of internal ports | API binds 127.0.0.1; only the web port is routed through the MacLustr Tunnel (TLS by Caddy); /api/metrics restricted to localhost |
| Supply chain | malicious deps | pinned minimum versions, uv/pnpm lockfiles, ruff/mypy/tests in CI (to add: pip-audit, pnpm audit in the runbook) |
| Jurisdiction / entitlements | assuming capabilities | pair status, leverage lists, minimums read live from AssetPairs; SystemStatus checked; preflight probes permissions at runtime |
Out of scope by design: custody/withdrawal workflows, margin/derivatives, multi-user RBAC (single owner role today —
the session carries a role claim so additional roles can be added without changing the cookie format).