Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Security model

The agent driving these tools can be prompt-injected, so execkit treats every tool argument as untrusted. Anything dangerous to the host or filesystem is controlled by the operator at startup through environment variables, never by a per-call agent argument. An injected agent cannot change where the audit log is written, which directory SSH keys come from, or the session limits.

Operator settings

Env varPurposeDefault
EXECKIT_MCP_AUDITappend a JSONL audit log of every command hereoff
EXECKIT_MCP_AUDIT_DIRone JSONL file per session in this directory (<session_id>-<open_ms>.jsonl); takes precedence over EXECKIT_MCP_AUDIToff
EXECKIT_MCP_AUDIT_RETENTION_DAYSdelete per-session log files older than N days at startup (dir mode only); 0 disables14
EXECKIT_MCP_KEY_DIRSSH key_path must canonicalize to inside this dir~/.ssh
EXECKIT_MCP_KNOWN_HOSTSSSH host-key verification file (TOFU; rejects changed keys)~/.ssh/known_hosts
EXECKIT_MCP_INSECURE_ACCEPT_ANY_HOSTKEYDANGEROUS disable host-key checksunset
EXECKIT_MCP_MAX_SESSIONSsoft cap on concurrent live sessions64
EXECKIT_MCP_SESSION_TTLreap sessions idle longer than N seconds; 0 disables1800
EXECKIT_MCP_POLICY_FILEJSON allow/deny (program names) + deny_patterns (regex) the agent cannot edit; advisoryoff

EXECKIT_MCP_KEY_DIR and EXECKIT_MCP_KNOWN_HOSTS default off the home directory, which resolves by priority ($HOME, then the passwd database), so the defaults are correct even when $HOME is unset. Run execkit-mcp doctor to see what each one resolves to on your machine.

What is enforced where

  • Host keys are verified by default (TOFU against known_hosts; a changed key is rejected as a likely MITM). Pin an exact key with fingerprint, or set the insecure env var only for throwaway hosts.
  • key_path is sandboxed to EXECKIT_MCP_KEY_DIR; traversal or out-of-bounds paths are rejected with a generic error that does not leak path existence.
  • The audit destination is operator-chosen, never a tool argument, so an injected agent cannot write to arbitrary files.
  • Docker sessions reach any container the daemon can see. Grant Docker access deliberately and scope the context.
  • The server speaks MCP on stdout; all diagnostics go to stderr.

The fence is advisory, not a sandbox

allow / deny command lists are defense in depth, not a jail. Matching on command strings is trivially bypassable (/bin/rm, $(echo rm), base64, bash -c "..."). Treat the fence as a guardrail against accidents and obvious mistakes.

The real security boundary is the operating system: run the agent’s shell as a least-privilege user, in a container, or on a scoped SSH account, so that even a fully compromised agent can only reach what that account can. execkit gives you visibility and undo on top of that boundary; it does not replace it.

Operator command policy

Point EXECKIT_MCP_POLICY_FILE at a JSON file to set an allow/deny fence the agent cannot edit (unlike the per-call allow/deny, which the agent supplies):

{
  "allow": ["git", "ls", "npm"],
  "deny": ["rm", "dd", "shutdown"],
  "deny_patterns": ["\\brm\\b", "kubectl\\s+delete", "git\\s+push\\s+.*--force"]
}
  • allow (program names): if non-empty, only these may run. Empty/absent = all.
  • deny (program names): always blocked; deny wins over allow.
  • deny_patterns (regex over the whole command): for what names cannot express.

Prefer a deny_pattern over a name deny for anything that matters: name matching only sees the program name per pipeline segment, so deny: ["rm"] misses sudo rm and xargs rm, while deny_patterns: ["\\brm\\b"] catches them. In JSON the regex backslashes double up (\\b); use (?i) for case-insensitive matching.

A blocked command never runs; it is recorded in the audit log, shown in watch, and pushed to the client as a warning. This is an ADVISORY guardrail, not a sandbox: string matching is trivially bypassable (/bin/rm, base64, bash -c). The real boundary is a least-privilege user, a container, or a scoped SSH account.