How your code, credentials, and sessions stay yours
Knockout sessions touch your real codebase, your real API keys, and chunks of every file the agent reads. None of that should sit unprotected on a server. The platform encrypts it with a key only you derive, refuses every plaintext write at both the application and database layer, and never holds your vault password.
Recent hardening
| Data | In the vault | Notes |
|---|---|---|
| Session prompts & responses | Encrypted | Every Knockout turn, system prompts, generated code |
| LLM provider API keys | Encrypted | OpenAI, Anthropic, Google, Groq, etc. |
| Signup IP | Encrypted | GDPR personal data |
| Last-login IP | Encrypted | GDPR personal data |
| Tool call outputs in session history | Encrypted | Captured inside the message stream |
| File paths & names quoted in prompts | Encrypted | Sit inside encrypted message bodies |
| Account email & username | Plaintext | Required plaintext for login + uniqueness |
| Account password hash | Plaintext | scrypt-hashed, never reversible |
| Wallet balance & subscription status | Plaintext | Required for billing flows |
Your vault password is never stored on the server, not even as a hash. We store only a random salt and an encrypted verifier (a known plaintext encrypted with your derived key). The server can prove your password is correct but cannot recover it or derive the key without it.
When you unlock the vault, the derived key is wrapped with the server master key and cached with a 1-hour rolling idle TTL. Extended only by real cryptographic use — not by status polls or forgotten tabs. An idle session dies and re-prompts; an actively used session can live indefinitely.
Knockout workers run on separate boxes from the web tier. They fetch a per-session, HMAC-signed vault lease over mTLS, hold the key in process memory only for the duration of the session, and never persist it. Each session gets its own lease scope — cross-session reuse is rejected.
A PostgreSQL CHECK constraint on ko_sessions requires is_encrypted=true OR legacy_plaintext=true. Even if a code path tried to write plaintext, the database would refuse. Defence in depth: the application refuses too.
unlock
verifier check
use
decrypt → +1 h
1 h idle
no crypto → expire
Status reads (isVaultUnlocked) are passive — they do NOT extend the TTL. Only real work does.
Each ko token has fine-grained scopes — session:create, sync:push, config:write. Tokens are stored as SHA-256 hashes server-side; the full token is shown once at creation and cannot be retrieved. Revoke any token instantly from Settings.
The CLI stores the vault password in your OS keychain — macOS Keychain, Linux libsecret, Windows Credential Manager — not in a plaintext config file. Existing plaintext passwords get migrated to the keychain on first run.
ko auth login opens a secure browser flow. You authenticate on the platform; the CLI receives a scoped token automatically. No passwords are typed into the terminal. CSRF state validation and reCAPTCHA protect the handshake.
Self-updates are verified with Ed25519 digital signatures. The signing public key is embedded in the binary at build time. Downloaded updates that don't match get rejected — protecting against MITM and tampered binaries on the update path.
The CLI's file Read/Write/Edit tools are restricted to your project's working directory. Symlink escapes are detected and blocked. Access to ~/.ssh, ~/.aws, ~/.gnupg, and other sensitive paths is denied by a hardcoded denylist.
The CLI detects and blocks compound shell commands (pipes, semicolons, backticks, subshells) in tool calls. Dangerous commands require explicit user approval. Server-side admin commands use execFile (no shell) with strict input validation.
Code pushed via ko sync push is encrypted on your machine before upload, using AES-256-GCM with a key derived from your vault password (scrypt). The platform stores only ciphertext.
The CLI's Web UI WebSocket binds to 127.0.0.1 only, validates Origin headers, and requires a one-time cryptographic nonce. Malicious websites and local processes cannot connect without it.
Every Knockout API endpoint is rate-limited — 5/min on auth routes, 20/min on resource creation, 30/min on mutations, 60/min on reads. In-memory sliding window per IP, blocks brute-force and abuse.
Every mutating browser request is validated against Origin and Referer headers. CLI requests use Bearer tokens and are stateless, so they bypass CSRF cleanly without losing protection on the browser path.
All inputs validated with length, type, enum, and regex constraints. Hostnames, SSH usernames, and ports use allowlist patterns. No unbounded input reaches the database.
HSTS (1 year), X-Frame-Options DENY, strict CSP, X-Content-Type nosniff, strict Referrer-Policy enforced on every response. frame-ancestors none prevents clickjacking.
Daily PostgreSQL dump → AES-256-CBC + pbkdf2 wrapper (passphrase only on the source box) → OVH S3. Two keys required to read: the backup passphrase plus every affected user's vault password. 30-day retention.
The restore script downloads, decrypts, and lands the dump into a separate fightclub_restore database — never the live DB without an explicit operator promotion. Row counts verified to match live during deploy.
By design, the vault password cannot be recovered. If you forget it, your encrypted sessions, API keys, and personal data are permanently unreachable. You can reset the vault — which deletes everything encrypted and lets you start fresh — but the old data is gone forever. This is the trade-off for true zero-knowledge security: nobody, not even us, can read your encrypted data without your password.
Save your vault password somewhere durable
Password manager, paper, anywhere that isn't this machine. If you forget it, every encrypted thing on the platform is gone — we cannot help you recover it.
Unlock the vault when you sit down to work
Click Unlock vault on the dashboard. The session rolls forward every time you actually use it. Forgotten tabs won't keep it alive — only real work does.
Lock the vault on shared computers before walking away
On a work laptop, university PC, or anywhere someone else might use the machine, explicitly lock + sign out. The login session itself auto-expires after 1 hour idle.
Clean up any ⚠ unencrypted sessions on your sessions list
Old rows from before the encryption rollout auto-upgrade the next time you open them with the vault unlocked, or you can Delete them to redact entirely.