Knockout Security

How your code, credentials and sessions stay yours

You have clicked "forgot password" on every site you have ever used, and it has always worked. Somebody on the other end could put you back in. That convenience is telling you something about where the keys live, and it is the one thing we deliberately gave up.

A Knockout session touches your real codebase, your real provider keys and a piece of every file the agent reads. Your machine turns your vault password into a key and encrypts that material before it goes anywhere. What lands on our side is ciphertext plus a random salt. We can store it, back it up and hand it back to you, and we cannot open it, because the password that derives the key never arrives here in the first place.

So the honest version of the promise is narrow and checkable. There is no plaintext copy on our side to leak, no support process that can decrypt your data for you and no recovery if you lose the password. The rest of this page is the mechanism, the parameters and the parts that are deliberately not encrypted.

Recent hardening

How your code is protected

1You set a vault password at signup (never stored on server, never recoverable)
2scrypt derives a 256-bit key from the password and a random 32-byte salt, at N=131072 (128 MB per attempt, which is what makes offline guessing expensive)
3Session messages, provider keys and personal data are encrypted with AES-256-GCM (authenticated encryption) before any row lands in the database
4Vault key is cached in vault_sessions, wrapped with the server key, with a 1 h rolling idle TTL extended only by real cryptographic use
5The ko CLI caches the same key in ~/.ko/credentials.json at mode 0600 on a 4 h rolling idle window; ko vault lock revokes the session and wipes the cache

What's encrypted

DataIn the vaultNotes
Session prompts & responses EncryptedEvery Knockout turn, system prompts, generated code
LLM provider API keys EncryptedOpenAI, Anthropic, Google, Groq, etc.
Signup IP EncryptedGDPR personal data
Last-login IP EncryptedGDPR personal data
Tool call outputs in session history EncryptedCaptured inside the message stream
File paths & names quoted in prompts EncryptedSit inside encrypted message bodies
Account email & username PlaintextRequired plaintext for login + uniqueness
Account password hash Plaintextscrypt-hashed, never reversible
Wallet balance & subscription status PlaintextRequired for billing flows

Architecture

Zero-knowledge design

Checking a password normally means comparing it to something stored. Here nothing is stored. When you set a vault password your machine derives a key from it, encrypts a small known phrase with that key and sends us the scrambled phrase and a random salt. Next unlock, we encrypt the same phrase again and check the results match. That proves you know the password while we hold neither it nor the key. It is also why anyone walking off with the whole database walks off with noise.

Session lifecycle

On unlock, the derived key is wrapped with the server master key and cached with a 1 hour rolling idle TTL on the web. Only real cryptographic use rolls that window forward. A status poll does not, so a forgotten tab checking whether the vault is unlocked cannot act as a heartbeat that keeps it unlocked. Web sessions also hit a 12 hour absolute cap. The ko CLI vault runs a 4 hour idle window on the same use-only rule, with no absolute cap.

Password change and recovery

Change the vault password and every provider key is decrypted under the old key and re-encrypted under the new one in a single pass, then every open vault session is invalidated so nothing keeps running on the key you just retired. Forget it and there is no recovery. We hold no copy to reset you back to, so the only way forward is to reset the vault and enter your provider keys again. That is the cost of the server never having the password in the first place.

Database-enforced invariant

A PostgreSQL CHECK constraint on ko_sessions requires is_encrypted=true OR legacy_plaintext=true. The application refuses plaintext writes on its own, and the constraint is there for the day a code path forgets. Two layers, because one of them is written by people.

Vault session lifecycle

unlock

verifier check

use

decrypt → +1 h

1 h idle

no crypto → expire

Status reads (isVaultUnlocked) are passive and do NOT extend the TTL. Only real cryptographic work does.

CLI hardening

Scoped API tokens

Each ko token carries fine-grained scopes such as session:create, sync:push and config:write, so a token minted for CI cannot rewrite your config. Server-side they are stored as SHA-256 hashes. The full token is shown once at creation and can never be read back, which also means a database dump yields nothing you can authenticate with. Revoke any token instantly from settings.

Vault password in the OS keychain

The CLI keeps the vault password in your operating system keychain (macOS Keychain, Linux libsecret, Windows Credential Manager) rather than in a plaintext config file. Passwords left in a config file by an older version get migrated into the keychain on first run.

Browser-based OAuth login

ko auth login opens a browser flow. You authenticate on the platform and the CLI receives a scoped token, so no password is ever typed into a terminal where a shell history or a screen recorder could catch it. CSRF state validation protects the handshake.

Update integrity

Every self-update is checked against a SHA-256 manifest fetched over TLS before it is applied. A mismatch is rejected, which stops a corrupted or tampered binary landing on the update path. Ed25519 signature verification of the release manifest is built and ships disarmed today; it becomes mandatory once the release-signing key is armed (coming soon).

Filesystem & tool safety

Working-Directory Boundary

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.

Command Injection Prevention

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.

Zero-Knowledge Snapshots

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.

Secure Local WebSocket

The Web UI defaults to loopback (127.0.0.1) and gates every WebSocket connection on a one-time cryptographic nonce plus an Origin check against the server's own host. So a malicious website or a stray local process cannot connect even if you deliberately bind it to a LAN address with --listen.

Platform API hardening

Tiered Rate Limiting

Every Knockout API endpoint is rate-limited by class: 5/min on auth routes, 20/min on resource creation, 30/min on mutations and 60/min on reads. Sliding window per IP, held in memory, which is enough to make credential stuffing pointless.

CSRF Protection

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.

Strict Input Validation

Every input is checked for length, type, enum membership and regex shape. Hostnames, SSH usernames and ports go through allowlist patterns. No unbounded input reaches the database.

Security Headers

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.

Backup & recovery

Doubly-Encrypted Backups

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.

Restore-Tested

The restore script downloads, decrypts and lands the dump into a separate fightclub_restore database. It never touches the live one without an explicit operator promotion. Row counts are verified against live during deploy, because an untested backup is a story rather than a backup.

No Password Recovery

The vault password cannot be recovered. Forget it and your encrypted sessions, provider keys and personal data are permanently unreachable. Resetting the vault is possible, and it deletes everything encrypted so you can start again with new keys. The old data does not come back. Nobody here has a copy of your key to fall back on, and the crypto forbids reconstructing it, which is exactly the property that makes the rest of this page true. Put the password in a password manager today.

What you should do

1

Save your vault password somewhere durable

Password manager, paper, anywhere that isn't this machine. Forget it and every encrypted thing on the platform is gone, and there is no support ticket that changes that.

2

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, and a forgotten tab polling for status will not keep it alive.

3

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.

4

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.

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 upgraded on unlock
Vault Salt
32 bytes (random per user)
Vault Key Size
256 bits
Vault Session TTL
web 1 h idle + 12 h cap; CLI 4 h idle
Token Storage
SHA-256 server, OS keychain client
Snapshot Encryption
AES-256-GCM, scrypt-derived
Update Integrity
SHA-256 manifest over TLS (live); Ed25519 signatures coming soon
Transport (public)
HTTPS, TLS 1.2+
Transport (internal)
mTLS, Knockout Internal CA v3
DB Constraint
is_encrypted OR legacy_plaintext
Backup Wrap
AES-256-CBC + pbkdf2
Backup Retention
30 days, OVH S3
Quantum Resistance
AES-256 (256-bit symmetric, ~128-bit vs Grover)

Every claim above is a property of how the thing is built rather than a policy we promise to follow. Set a vault password, unlock it, and check the behaviour against this page.