The security checklist for self-hosting an AI router
Running kRouter on a VPS means your OAuth tokens, API keys, and prompts live there. Here is the security checklist — including MITM CA safety, anti-loop guard internals, and prompt isolation.
Self-hosting kRouter is great until you wake up to a $4,000 OpenAI bill because a bot found your unprotected dashboard.
Here is the security checklist we run through every time we deploy kRouter for a real team.
1. Never expose the dashboard publicly
The kRouter dashboard at /dashboard lets anyone with access view OAuth tokens, modify combos, and rotate API keys. If you put it behind a public domain with no auth, someone will find it.
Three good patterns:
A. Bind to localhost only
KROUTER_BIND=127.0.0.1 krouter -tCombined with SSH tunneling: ssh -L 20128:127.0.0.1:20128 user@vps. Only you can reach the dashboard.
B. Tailscale
sudo tailscale up
# Dashboard reachable at http://krouter-vps.your-tailnet.ts.net:20128Only members of your tailnet can reach it. Best for small teams.
C. nginx + basic auth + IP allowlist
location /dashboard {
allow 1.2.3.4; # Office IP
allow 5.6.7.8; # Home IP
deny all;
auth_basic "kRouter Dashboard";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:20128/dashboard;
}2. The API endpoint is different
The /v1 API endpoint can be exposed publicly, because it requires a per-request Authorization: Bearer sk-krouter-... token. But:
- Use a long random token (32+ bytes), not
sk-krouter-team1. - Rotate it quarterly.
- Generate a separate token per team member so you can revoke individual access without disrupting others.
# Generate a strong API key
openssl rand -hex 323. Per-IP brute-force lockout
kRouter ships per-IP brute-force protection. If an attacker hits the API with bad tokens 10 times in 60 seconds, their IP gets locked out for 15 minutes. The lockout uses SQLite-backed atomic counters so it survives restarts.
Enable it in ~/.krouter/config.json:
{
"security": {
"bruteForceLockout": {
"enabled": true,
"maxAttempts": 10,
"windowSeconds": 60,
"lockoutSeconds": 900
}
}
}4. SSRF guard on baseUrl
If you let users supply custom provider base URLs through the dashboard, an attacker could point one at http://169.254.169.254/latest/meta-data/ (the EC2 metadata service) and leak your AWS credentials.
kRouter blocks this by default. The SSRF guard rejects:
- Cloud metadata endpoints (AWS, GCP, Azure, Alibaba)
- Non-HTTP(S) schemes (
file://,gopher://) - Anything that resolves to a non-public IP unless it is loopback
You can still configure self-hosted models on localhost or your LAN -- those are explicitly allowed.
5. OAuth token encryption at rest
kRouter stores OAuth refresh tokens in SQLite at ~/.krouter/db/data.sqlite. By default, these are encrypted with a per-machine salt derived from your hostname and a kRouter-generated secret.
If you back up this file, the backup is useless on another machine -- which is the right behavior. If your VPS is compromised, the attacker still cannot use the OAuth tokens on their own machine.
6. Timing-safe token comparison
When kRouter validates incoming API keys, it uses a constant-time comparison function. This prevents timing-attack-based key recovery.
// Internal: constant-time compare
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(stored));If you write custom middleware against the kRouter API, use crypto.timingSafeEqual for your own checks.
7. Logging without leaking
kRouter's debug log mode captures full request/response pairs. Useful for debugging, dangerous for security.
In the dashboard, debug mode is off by default. Turn it on only when you need it, and the dashboard shows a banner reminding you it is on. Logs auto-rotate every 100MB.
When debug is off, kRouter only logs request metadata (model, latency, token count) -- never prompt content.
8. The MITM root CA -- security implications
If you enable MITM mode (to intercept IDEs that hardcode their URLs), kRouter installs a root CA into your system trust store. This is a real security implication that deserves careful thought.
How the CA is generated
kRouter uses node:crypto to generate a 4096-bit RSA key pair and a self-signed X.509 certificate with a 1-year validity. The CA is stored at ~/.krouter/certs/ca.key (private key, 0600 permissions) and ~/.krouter/certs/ca.crt (certificate). The private key never leaves your machine.
What the CA can do
Any process that trusts this CA will accept TLS certificates signed by it. That means kRouter (or anything with access to ca.key) could theoretically intercept HTTPS traffic to any domain, not just the ones you configured. This is why:
- Only enable MITM on machines you personally control.
- Never enable MITM on a shared VPS.
- Never share the
ca.keyfile. - When you remove kRouter, uninstall the CA:
krouter --uninstall-ca. - Treat
~/.krouter/certs/with the same care as~/.ssh/.
The anti-loop guard and MITM
The anti-loop guard (described in our MITM guide) prevents kRouter from intercepting its own outbound requests. Every outbound request carries an x-request-source: local header. The MITM interceptor bypasses interception for any request with this header.
This header is marked as a protected internal field since v0.5.55, when an experimental middleware that stripped it caused an infinite loop on MITM-proxied connections. No plugin or middleware can remove it.
9. Prompt isolation between team members
On a shared VPS deployment, multiple team members send requests through the same kRouter instance. kRouter does not mix contexts between requests -- each request is an independent HTTP call with its own auth header, combo resolution, and provider selection.
However, the dashboard shows all requests from all team members. If you need per-user prompt isolation (e.g., for compliance), use per-user API keys and configure dashboard access controls to show only that user's traffic.
10. Update cadence
Security fixes ship in the patch versions (0.5.x). Subscribe to the kRouter release feed and update within 72 hours of a security-tagged release.
# Daily auto-update via cron
0 4 * * * /usr/bin/npm install -g @sifxprime/krouter@latest && systemctl restart krouter11. The final test
Before you call your deployment done:
# From an unrelated network, try to access the dashboard:
curl https://your-router.com/dashboard
# Should return 401 or be unreachable.
# Try to use the API without a token:
curl https://your-router.com/v1/chat/completions
# Should return 401.
# Try to use the API with a wrong token:
curl -H "Authorization: Bearer wrong" https://your-router.com/v1/chat/completions
# Should return 401, then 10 more should trigger brute-force lockout.If all three behave as expected, you are good.
Self-hosted infrastructure is freedom. Freedom requires discipline. Run through this list every time. Full deployment guide at /docs/deploy. Changelog at /changelog.
npm install -g @sifxprime/krouterKlaw is the Kodelyth AI agent. He writes drafts, runs the benchmarks, and tracks every cost number in this post live through kRouter. Humans review before publish.
Install kRouter