Security
kimbap runs with real privilege on your host — it can install system packages, manage a reverse proxy on ports 80/443, and start/stop arbitrary Docker containers. This page covers the security-relevant decisions worth knowing about.
Secrets
- Passwords are hashed with argon2id (the current OWASP-recommended default), stored as a self-describing PHC string so cost parameters can change later without a migration.
- Session tokens and API keys are 256-bit random values; only their SHA-256 hash is ever persisted. The raw value is shown exactly once, at creation. SHA-256 (not a slow hash) is correct here — these are high-entropy random tokens, not low-entropy user input.
- API keys are prefixed
kbp_so they're recognizable at a glance (and by secret-scanning tools) if one ever leaks somewhere it shouldn't.
Sessions
HttpOnly,SameSite=Laxcookie.Secureis set once kimbap detects it's being reached over HTTPS (directly, or viaX-Forwarded-Proto: httpsfrom Traefik) — it's not set on the plain-HTTP bootstrap port, since there's no TLS there to protect the cookie with in the first place.- Sliding expiry (~30 days idle) with a server-side row per session, so logging out (or an admin disabling a user) actually revokes access — unlike a bare JWT, which would need its own revocation list to do the same thing.
Rate limiting
Both login and API-key validation are rate-limited per source IP (10 failures/minute → 5-minute lockout for logins; 20/minute for API keys) to blunt brute-force attempts, independent of password/key strength.
Roles
Two roles: admin (users, Docker/Traefik system actions, every project) and
member (project CRUD/lifecycle only). API keys and MCP tool calls inherit
the role of the user that issued them — there's no standalone "root key"
disconnected from a real account.
Confirmation gating
Host-level or destructive actions — installing/updating Docker, provisioning
Traefik, deleting a project — require an explicit confirm: true in the
request body (REST) or tool arguments (MCP), and (for the system-level ones)
the admin role. This matters most for MCP: an LLM acting on a
loosely-worded instruction shouldn't be able to trigger a host-level change
without a clear, deliberate confirmation in the actual tool call.
Audit log
Every mutating action — through the UI, REST API, or MCP — is recorded in
audit_log with the actor, action, target, and a detail blob (e.g. command
output for lifecycle actions). GET /api/audit (admin only) or the
list_audit_log MCP tool surface it.
Systemd hardening
The installed unit runs kimbap under a dedicated system user with:
AmbientCapabilities=CAP_NET_BIND_SERVICEonly (no full root, even though it may occasionally bind a low port directly).ProtectSystem=strict,ProtectHome=true, a narrowReadWritePathsscoped to the state directory.NoNewPrivileges=true, kernel/namespace/SUID restrictions, and aSystemCallFilter=@system-serviceallowlist.
See kimbap install's rendered unit (systemctl cat kimbap on an installed
host) for the complete set.
Docker socket access
Once Docker is installed, kimbap's system user is added to the docker
group so it can talk to the Docker socket. This is a well-known
privilege-equivalent-to-root tradeoff inherent to any tool that manages
Docker containers on a host (not specific to kimbap) — anyone who can reach
the Docker socket can, in the general case, escape to root on the host.
Treat kimbap's admin account, and any admin-scoped API/MCP key, with the same
care you'd give root/sudo access.
Reporting a vulnerability
Open an issue on the GitLab project or contact the maintainer directly for anything sensitive enough to want a private channel first.