Security
How kRouter handles credentials, secrets, certificates, and exposes itself to the network. Threat model included.
kRouter runs on your machine. The threat model is: you trust the binary, but nothing else. We don't run any service on your behalf — your prompts never leave your computer except to the upstream AI provider you configured.
Credential storage
Every OAuth refresh token, API key, and provider session lives in your local SQLite at ${DATA_DIR}/db/data.sqlite. They are:
- Encrypted at rest with a per-machine salt
- Never transmitted to any kRouter-controlled service (there isn't one)
- Never logged even with
ENABLE_REQUEST_LOGS=true - Deletable in one step:
rm -rf ~/.krouterwipes everything
Dashboard authentication
The dashboard ships behind a JWT-cookie auth gate. First login uses INITIAL_PASSWORD (default 123456 — change it in production). Subsequent logins use the password hash stored in SQLite.
Sessions:
- Cookie name:
krouter_session - Signed with
JWT_SECRET(auto-generated if unset) - Sliding 7-day expiry
Secureflag auto-set whenAUTH_COOKIE_SECURE=true- Timing-safe compare for password verification
- Per-IP brute-force lockout (10 attempts → 1 hour cooldown)
API key authentication (/v1/*)
By default kRouter accepts requests on /v1/* without auth (local-only use). For public endpoints set:
export REQUIRE_API_KEY=trueThen generate keys in Dashboard → API Keys. Each key:
- Has the prefix
sk-krouter-so it's distinguishable - Is hashed via HMAC-SHA256 with
API_KEY_SECRETbefore storage - Can be revoked from the dashboard at any time
- Carries per-key rate limits (configurable)
SSRF guards on custom providers
Some providers let you specify a custom baseUrl (OpenAI-compatible, Anthropic-compatible, Ollama-local). To prevent SSRF attacks via that field, kRouter validates and rejects:
- Cloud metadata endpoints:
169.254.169.254(AWS),100.100.100.200(Alibaba),metadata.google.internal(GCP),169.254.170.2(ECS) - Non-
http(s)schemes (nofile://, nogopher://) - IPv6 link-local (
fe80::/10) - Wildcard
0.0.0.0/::
Loopback (127.0.0.1) and private LAN ranges remain allowed — they are legitimate destinations for self-hosted Ollama, LM Studio, etc.
MITM mode (advanced)
Some IDEs (Cursor, Antigravity, Kiro IDE, Claude Code in some configs) talk to a hardcoded backend. To route them through kRouter, MITM mode installs a local root CA and resolves those specific hostnames to 127.0.0.1.
This is technically a man-in-the-middle setup:
- A root CA is generated at
${DATA_DIR}/certs/root.crtand installed in your OS trust store - DNS entries are added to
/etc/hosts(or Windows equivalent) for the intercept hostnames - kRouter terminates TLS with that CA, inspects + routes the request, returns a re-encrypted response
Trust boundaries:
- The root CA is only trusted by your machine
- It is never transmitted anywhere
- Removing kRouter removes the trust automatically (or you can
rmthe cert file and run the OS uninstall command — printed in the dashboard) - MITM mode requires admin privileges to bind
:443and edit/etc/hosts - MITM mode is off by default — opt in per-provider
If MITM mode worries you, don't enable it. kRouter works fine without it for OpenAI/Anthropic-compatible providers.
What kRouter does NOT do
- It does NOT phone home
- It does NOT transmit telemetry
- It does NOT include analytics, third-party scripts, or fingerprinting
- It does NOT have any backend service we operate
- It does NOT log your prompts or completions even with debug enabled (only metadata: timestamp, model, token count, latency, status)
Auditing
The full source is at github.com/sifxprime/krouter. Every release is signed and tagged. The Docker image manifest is reproducible — same commit, same output.
For a security report or responsible disclosure, open a private security advisory on the GitHub repo.
Where to go next
- Deployment — production setup
- Architecture — internal routing engine
- Core Concepts — MITM mode in detail