Back to Feed

Your Data , Your Keys

Per-user encryption with a password we never store

When you mark a fight as private, Fight Club encrypts every piece of content, topics, messages, documents, AI-generated summaries, with a key derived from your personal vault password. We never store that password, only a salt and a verifier we can test it against. Lock the vault or leave it idle and your content is unreadable to us. Built on AES-256-GCM, which NIST rates as quantum-resistant.

Recent hardening

  • Vault is now mandatory at registration. New accounts cannot exist without a vault, so there is no window where a user is authenticated but unprotected. Existing vaultless accounts get a forced setup screen on next login.
  • Plaintext writes refused at the database layer. A CHECK constraint on Knockout session content requires every new row to be vault-encrypted. The application code also refuses to write plaintext, so the silent “vault locked → store unencrypted” fallback that previously existed is closed at two layers.
  • Auto-migration of personal data into the vault. On every vault unlock, any plaintext content from before this rollout (Knockout messages, signup IP, last-login IP) is encrypted with your vault key and the plaintext is cleared. Best-effort, idempotent, no operator action required.
  • Vault session lifetime is 1 hour idle, 12 hour absolute cap. Rolled forward only by real cryptographic use, so a forgotten browser tab cannot keep the vault alive via background polling. Even an actively-used session locks 12 hours after unlock and re-prompts for your password.
  • Database backups now ship encrypted to OVH S3. Daily AES-256-CBC encrypted dump, 30-day retention, restore tested. The local-on-replica copy was purged after cutover.

How It Works

Think of the vault password as the only copy of a key to a safe deposit box. You type it in, we turn it into an encryption key on the spot, use it to lock your content, then forget the password itself. What's left on our servers is a random salt and a small encrypted token we can test your password against. Get the password right and the token decrypts. Get it wrong and it doesn't. That's all we can tell.

There is an honest limit to this design. While your vault is unlocked, we hold the derived key so your fights can actually run, and during that window our servers can read your content. Lock it, or leave it idle for an hour, and the key is gone from our side. Forget the password and it is gone from everyone's side, permanently, including ours.

1You set a vault password (never stored on server)
2scrypt derives a 256-bit key from password + random salt
3Vault key encrypts content via AES-256-GCM (authenticated encryption)
4Vault key is cached encrypted in session (1h rolling idle, extended only by real cryptographic use)

What's Encrypted

DataPrivate FightPublic Fight
Fight title & topic EncryptedPlaintext
All debate messages EncryptedPlaintext
Uploaded documents (PDF, images) EncryptedPlaintext
Extracted PDF text EncryptedPlaintext
Fighter personas & system prompts EncryptedPlaintext
AI-generated summaries EncryptedPlaintext
API keys (all providers) Encrypted Encrypted
RAG endpoint keys Encrypted Encrypted

Architecture

Password Never Stored

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 verify your password is correct but cannot recover it or derive your vault key without it. So a locked or idle vault is unreadable to us, and a forgotten password is unrecoverable by anyone.

Session Management

When you unlock your vault, the derived key is encrypted with the server's master key and cached with a 1-hour rolling idle TTL. The window is extended only by actual cryptographic use (encrypting an API key, running a fight, sending a Knockout turn), not by background status polls or a forgotten browser tab. An idle session dies in an hour, and an absolute 12-hour cap locks even an actively-used one, so you re-enter the password at least twice a day.

File Encryption

Uploaded documents (PDFs, images) are encrypted on disk using AES-256-GCM with your vault key. The binary format prepends the IV and auth tag directly to the ciphertext, no hex encoding overhead. Files are decrypted only when served to the authenticated owner.

Server-Side Security

A separate server master key (AES-256, from environment variable) provides a second encryption layer for vault session keys at rest. All communication happens over HTTPS. CSRF protection guards browser mutations, and rate limiting covers the authentication and high-value API endpoints.

No Password Recovery

Forget your vault password and your data is gone. Not "contact support" gone. Gone. We can't reset it, we can't recover it, and no amount of proving who you are will change that, because the thing that decrypts your data was never persisted on our servers to begin with. You can reset the vault to start fresh, which wipes the old encrypted content for good. That is the deal you get in exchange for a locked vault we cannot read. Write the password down somewhere safe.

Quantum-Resistant by NIST Standards

Fight Club uses AES-256, which NIST classifies as quantum-resistant. While Grover's algorithm theoretically halves symmetric key strength against a quantum computer, AES-256 would still provide an effective 128-bit security level, far beyond what is computationally feasible.

Post-quantum threats primarily target asymmetric cryptography (RSA, ECDH, ECDSA) used in key exchange and digital signatures. Our vault uses only symmetric primitives, scrypt for key derivation and AES-256-GCM for authenticated encryption, both of which remain secure in a post-quantum world.

NIST's post-quantum standardization effort (FIPS 203/204/205) does not address symmetric encryption because AES-256 is already considered sufficient for the post-quantum era.

Technical Specifications

Encryption Algorithm
AES-256-GCM
IV Length
12 bytes (random per operation)
Auth Tag
16 bytes (tamper detection)
Key Derivation
scrypt (N=131072, r=8, p=1; legacy vaults N=16384, auto-upgraded)
Salt
32 bytes (random per user)
Vault Key Size
256 bits (32 bytes)
Session TTL
1 hour rolling idle, 12 hour absolute cap (extended only on cryptographic use)
Transport
HTTPS (TLS 1.2+)
Format (text)
iv:authTag:ciphertext (hex)
Format (files)
IV‖authTag‖ciphertext (binary)
Quantum Resistance
AES-256 (NIST post-quantum safe)

Knockout CLI Security

Defense-in-depth for your code, credentials, and sessions

Knockout is built with the same security-first mindset as Fight Club. Your code never leaves your machine unencrypted, API tokens are hashed and scoped, and every layer, from the CLI to the platform API, is hardened against real-world threats.

Authentication & Tokens

Scoped API Tokens

Each CLI token has fine-grained scopes, session:create, sync:push, config:write, etc. Tokens are stored as SHA-256 hashes on the server; the full token is shown only once at creation and cannot be retrieved again. You control exactly what each token can do.

Vault Password in OS Keychain

Your vault password is stored in the OS keychain (macOS Keychain, Linux libsecret, Windows Credential Manager), not in a plaintext config file. Existing plaintext passwords are automatically migrated to the keychain on first run.

Browser-Based OAuth Login

ko auth login opens a secure browser flow, you authenticate on the platform, and the CLI receives a scoped token automatically. No passwords are typed into the terminal. The flow is protected by CSRF state validation.

Token Expiration & Revocation

Tokens can be created with expiration dates for time-limited access. Revoke any token instantly from the Settings page or via the API. Every token usage is tracked with lastUsedAt timestamps so you can audit activity.

Code & Data Protection

Encrypted Code Snapshots

Code snapshots pushed via ko sync push are 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 key comes from a password we never store, so a locked vault leaves your code unreadable to us.

Encrypted Sessions & Pipelines

When your vault is unlocked, session messages and pipeline configurations are encrypted with your vault key before storage in the database. When your vault is locked, encrypted data is inaccessible, the server returns a “vault locked” response instead of plaintext.

File Tool Boundaries

The CLI's file read/write/edit tools are restricted to your project's working directory. Symlink escapes are detected and blocked. Access to sensitive paths like ~/.ssh, ~/.aws, and ~/.gnupg is denied by a hardcoded denylist.

Command Injection Prevention

The CLI detects and blocks compound shell commands (pipes, semicolons, backticks, subshells) in tool calls. Dangerous commands always require explicit user approval. Server-side admin commands use execFile (no shell) with strict input validation.

Platform API Hardening

Tiered Rate Limiting

Sensitive Knockout API endpoints are rate-limited with tiered limits, 5/min for auth, 20/min for resource creation, 30/min for mutations and 60/min for reads. The tiers cover authentication, vault unlock, resource creation and mutation routes. An in-memory sliding window per IP throttles brute-force and abuse.

CSRF Protection

Every mutating API request (POST/PUT/DELETE) from the browser is validated against Origin/Referer headers. CLI requests authenticate via Bearer tokens and bypass CSRF (stateless, no cookies). This prevents cross-site request forgery from malicious websites.

Input Validation

All inputs are validated with strict constraints, field lengths, type checks, enum whitelists, regex patterns, and semver format checks. Hostnames, SSH users, and ports are validated with allowlist patterns. No unbounded inputs reach the database.

Security Headers

HSTS (1 year), X-Frame-Options DENY, strict Content-Security-Policy, X-Content-Type-Options nosniff, and strict Referrer-Policy are enforced on every response via Next.js middleware. Frame-ancestors set to none prevents clickjacking.

Supply Chain & Integrity

Binary Update Integrity

Signatures coming soonToday, CLI self-updates are downloaded over HTTPS and checked against the SHA-256 checksums in the release manifest, so a corrupted or truncated binary is rejected. The Ed25519 signing path is built and tested (the verifier and the release signing step both exist), and we are arming it next so every binary also verifies an Ed25519 signature before it runs. Until then, transport security is TLS, not per-binary signature verification.

Signed Skill Marketplace

Skills installed from the marketplace are verified with Ed25519 signatures. Unsigned global skills are blocked unless explicitly trusted by the user. Project-level skills (in your repo) are loaded without signature requirements since they're under your version control.

Secure Local WebSocket

The CLI's local Web UI WebSocket server binds to 127.0.0.1 only, validates Origin headers, and requires a one-time cryptographic nonce for connection. Malicious websites and local processes cannot connect without the nonce.

Token-Free Streaming

SSE connections use one-time stream tickets (30-second TTL, single-use) instead of embedding API tokens in URLs. This prevents token leakage through server access logs, proxy logs, and browser history.

Knockout Technical Specifications

Token Storage
SHA-256 hash (server), OS keychain (client)
Snapshot Encryption
AES-256-GCM (scrypt-derived key)
Session Encryption
AES-256-GCM (vault key)
Binary Integrity
SHA-256 checksum vs manifest (Ed25519 signatures coming soon)
Skill Signatures
Ed25519 (SHA-256 digest)
CSRF Protection
Origin/Referer header validation
Rate Limiting
In-memory sliding window (5-60 req/min)
WebSocket Auth
Nonce + Origin validation
Stream Auth
One-time tickets (30s TTL)
File Boundaries
Working directory + sensitive path denylist
Transport
HTTPS (TLS 1.2+)
Token Scopes
7 granular permissions