Skip to content

Security ​

CommandGovernor ​

The CommandGovernor sits between LLM tool decisions and shell execution. It runs before run_command, run_script, and manage_process.

Blocked (CRITICAL) ​

These patterns are blocked before the command reaches a shell. With tools.governor.admin_can_override: true (the schema default and the tracked template), an admin-tier requester can override the block; the override is annotated in the output and recorded in the audit log. Set it to false to make the block absolute.

PatternReason
rm -rf /Recursive delete on root
mkfsFilesystem format
dd if=Raw disk write
Fork bombsSystem destabilization
shutdown, reboot, haltSystem control
chmod -R 777 /World-writable root
iptables -FFirewall flush
ufw disableFirewall disable
DROP TABLE, TRUNCATEDatabase destruction
crontab -rRemove all cron jobs
> /dev/sd*Block device write

Always Blocked: Unconditional Git Force Pushes ​

The governor blocks literal git push invocations that use --force, -f (including short-option bundles), or a force-prefixed +<refspec>. This rule is not admin-overridable. --force-with-lease and --force-if-includes are not mistaken for unconditional force, but combining either with --force, -f, or a + refspec is still blocked.

This is a bounded, quote-aware recognizer for literal shell commands. It handles ordinary shell control operators, Git global options such as -C, environment assignments, and common sudo, env, command, exec, and nohup wrappers. The literal tokenizer preserves comment-ending newlines, joins unquoted and double-quoted backslash-newline continuations, and distinguishes quoted or escaped separator arguments from actual operators. A mid-word # is literal. It recognizes else branches and separate or attached values for env -u / --unset and -C / --chdir. It is not a complete shell interpreter: aliases, functions, runtime expansion, eval, generated arguments, and command strings handed to another interpreter cannot be resolved statically. Redirections, heredocs, compound shell grammar, and interpreter-specific syntax are not fully parsed. An allowed result is not proof that arbitrary shell code cannot force-push. Those limitations must not be treated as a safe way to bypass the policy.

This rule does not replace the removed git_ops push safeguards. It does not perform the former freshness preflight or stale-branch refusal, bind the source and destination to the preflighted commit, obtain an observed remote SHA for an exact lease, or refuse a push when that evidence is missing. Operators using shell Git commands must do those steps explicitly before an allowed --force-with-lease=<destination>:<observed-sha> push.

Blocked (Exfiltration) ​

PatternReason
curl | bash, wget | shPipe remote script to shell
bash -i >& /dev/tcp/Reverse shell
nc -e /bin/shNetcat reverse shell
python -c socket.connectPython reverse shell
base64 -d | bashObfuscated payload
> /etc/passwd, > /etc/shadowAuth file writes
>> /etc/cron*Cron persistence

Allowed with Annotation (HIGH) ​

Commands classified as HIGH risk are allowed but annotated in tool output:

[governor: allowed — high risk, recursive delete]

Examples: rm -rf /tmp/specific_dir, systemctl restart nginx, and docker rm container.

Denial Response ​

When a command is blocked, the tool returns a structured denial:

Blocked [critical]: recursive delete on root
Suggested alternative: Use a more specific path, e.g. rm -rf /tmp/specific_dir

Permissions ​

Three tiers control tool access:

TierToolsUse Case
adminAll 67 built-in toolsOperators
user11 tools: ten read-only plus list managementTeam members
guestNone (chat only)Restricted

User-tier tools: get_tool_output, search_history, search_knowledge, web_search, fetch_url, list_schedules, list_tasks, list_skills, list_knowledge, manage_list, parse_time. run_command is deliberately excluded (arbitrary shell execution). manage_list can change list state; the rest are read-only. Host access is enforced separately per user at execution time.

Set default in config, override per-user via set_permission or web UI.

Secret Scrubbing ​

All input/output paths scrub secrets:

  • Discord messages (inbound) — detected and deleted
  • Tool results (outbound) — scrubbed before display
  • Audit logs — tool_input string values scrubbed
  • Bot message buffer — scrubbed before entering LLM context
  • File attachments — scrubbed before context injection

Patterns detected: Discord tokens, API keys, Bearer tokens, SSH private keys, AWS credentials, database URLs with passwords.

Web API Authentication ​

  • All /api/* endpoints require Bearer token auth when web.api_token is configured
  • Session-based auth via /api/auth/login
  • Web chat uses server-side identity — caller cannot spoof user_id
  • WebSocket connections authenticate via query parameter token

Skill Sandboxing ​

Skills run in-process as trusted plugins (not sandboxed). Mitigations:

  • Admin-only creation by default
  • Validation versus loading — standalone AST validation does not execute code. Trusted local create/edit loads Python before validating the runtime definition; URL install additionally runs static validation and prohibited-construct checks before loading. None of these checks is a sandbox.
  • Safe tool allowlist — skills cannot call run_command, apply_patch, etc. directly
  • Blocked file paths — cannot read .env, SSH keys, credentials
  • Blocked URLs — localhost, private IPs blocked unless whitelisted
  • Resource limits — 120s timeout, 50 tool calls, 20 HTTP requests

Codex Auth ​

  • OAuth tokens stored with 0600 permissions
  • Atomic writes (temp + fsync + rename) prevent corruption
  • Existing split-account files preserved on restart (no stale overwrite)
  • HTTP requests to token endpoint have 30s timeout

Released under the MIT License.