Shell Command Allow and Deny Lists
You control which shell commands tasks can execute on a hosted gateway through allowed_commands and blocked_commands in your declarative configuration. These lists are evaluated before risk classification — denied commands never reach the approval flow.
Use this page when
- You are creating or modifying allow/deny lists that control which shell commands the hosted gateway can execute.
- You need the YAML syntax for command patterns including wildcards, argument constraints, and scope overrides.
- You want to verify that a specific command is allowed or blocked before deploying the configuration.
Primary audience
- Primary: Technical Engineers
- Secondary: AI Agents, Technical Leaders
How Allow and Deny Lists Work
Task requests command execution
→ Check blocked_commands → DENY if matched
→ Check allowed_commands → DENY if not matched
→ Proceed to risk classification and approval flow
The deny list takes priority. If a command matches both the allowed list and the blocked list, it is denied.
Configuration Structure
hosted_gateway:
shell:
enabled: true
allowed_commands:
- git
- npm
- cargo
- make
- node
- python3
- cat
- ls
- find
- grep
- head
- tail
- wc
- echo
- date
blocked_commands:
- "rm -rf /"
- "rm -rf /*"
- chmod
- chown
- sudo
- su
- mount
- umount
- mkfs
- fdisk
- reboot
- shutdown
- iptables
- ufw
approval_required_risk_levels:
- destructive
- critical
command_timeout_seconds: 120
max_output_bytes: 1048576
Configuration Fields
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Whether shell command execution is active |
allowed_commands | list | [] | Commands permitted to execute (allowlist) |
blocked_commands | list | [] | Commands unconditionally denied (denylist) |
approval_required_risk_levels | list | [destructive, critical] | Risk levels that require user approval |
command_timeout_seconds | integer | 120 | Maximum execution time before a command is killed |
max_output_bytes | integer | 1048576 (1 MB) | Maximum command output captured and returned to the task |
Allowed Commands
When allowed_commands is configured, only commands whose binary name matches an entry in the list can execute. Commands not in the list are denied before classification.
Matching Rules
- Entries match the primary binary name of the command
gitmatchesgit status,git commit,git push, etc.npmmatchesnpm run build,npm install,npm test, etc.- Entries do not match arguments — use
blocked_commandsfor argument-level restrictions
Empty vs. Absent
- Empty list (
allowed_commands: []) — no commands can execute (effectively disables shell access) - Absent (field not specified) — all commands are allowed unless explicitly blocked
Blocked Commands
Commands matching blocked_commands are unconditionally denied. No approval flow is triggered. The command simply cannot run.
Matching Rules
- Entries can match binary names:
chmodblocks allchmodinvocations - Entries can match binary + argument prefixes:
rm -rf /blocks that specific invocation - Entries can use glob patterns:
rm -rf /*blocks recursive deletion of root-level directories - Matching is prefix-based for multi-word entries
Priority
The blocked list always wins. Even if rm appears in allowed_commands, adding rm -rf to blocked_commands prevents recursive removal while still allowing rm single-file.txt.
Common Engineering Configurations
Node.js / TypeScript Project
hosted_gateway:
shell:
enabled: true
allowed_commands:
- node
- npm
- npx
- git
- cat
- ls
- find
- grep
- head
- tail
- wc
- echo
- tsc
- eslint
- prettier
blocked_commands:
- "rm -rf /"
- "rm -rf /*"
- "rm -rf ~"
- chmod
- chown
- sudo
- curl -X DELETE
- curl -X PUT
command_timeout_seconds: 180
max_output_bytes: 2097152
Rust Project
hosted_gateway:
shell:
enabled: true
allowed_commands:
- cargo
- rustc
- rustfmt
- clippy-driver
- git
- make
- cat
- ls
- find
- grep
- head
- tail
- wc
- echo
blocked_commands:
- "rm -rf /"
- "rm -rf /*"
- chmod
- chown
- sudo
- "cargo install"
- iptables
command_timeout_seconds: 300
max_output_bytes: 2097152
CI/CD Pipeline
hosted_gateway:
shell:
enabled: true
allowed_commands:
- git
- docker
- make
- npm
- cargo
- python3
- cat
- ls
- find
- grep
- echo
- curl
- jq
blocked_commands:
- "rm -rf /"
- "rm -rf /*"
- "docker system prune"
- "docker volume rm"
- sudo
- chmod
- chown
- reboot
- shutdown
- iptables
approval_required_risk_levels:
- destructive
- critical
command_timeout_seconds: 600
max_output_bytes: 5242880
Read-Only Analysis
hosted_gateway:
shell:
enabled: true
allowed_commands:
- cat
- ls
- find
- grep
- rg
- head
- tail
- wc
- echo
- date
- git log
- git status
- git diff
blocked_commands:
- rm
- mv
- cp
- mkdir
- touch
- chmod
- chown
- sudo
approval_required_risk_levels:
- moderate
- destructive
- critical
command_timeout_seconds: 60
max_output_bytes: 524288
Command Timeout
The command_timeout_seconds setting limits how long any single command can run:
- When the timeout is reached, the command process is killed
- The task receives a timeout error with whatever output was captured before termination
- An audit event records the timeout with the command and duration
- The default is 120 seconds (2 minutes)
Set longer timeouts for build commands (cargo build, npm run build) and shorter timeouts for analysis commands (grep, cat).
Max Output Bytes
The max_output_bytes setting limits how much command output is captured:
- Output beyond this limit is truncated
- The task receives the truncated output with a truncation indicator
- This prevents a single command from consuming excessive memory
- The default is 1 MB
This limit applies to combined stdout and stderr.
Security Considerations
The Chat Approval UI
When a command requires approval, the chat interface shows:
- The command preview (the command string)
- The working directory
- The risk level and classification reason
The approval UI never shows:
- Full command output (output is only available after execution)
- Environment variables or their values
- File contents from the gateway host
- Credentials or secrets
Defense in Depth
Allow and deny lists are one layer of defense. Even if a command passes the lists:
- Risk classification still applies
- Approval requirements still apply (for destructive/critical commands)
- Policy chain enforcement still applies
- Network controls still apply (for commands that make network requests)
- Wallet controls still apply (for commands with associated costs)
Updating Lists
When you update allowed_commands or blocked_commands in your configuration:
- The gateway applies the new lists on the next config reload
- In-flight tasks are not retroactively affected
- New command requests from paused tasks use the updated lists
- An audit event records the configuration change
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Command denied but expected to work | Binary not in allowed_commands | Add the binary name to the allowed list |
| Command denied despite being in allowed list | Also matches a blocked_commands entry | Remove the conflicting blocked entry or use a more specific block pattern |
| Command times out | command_timeout_seconds too low | Increase timeout for long-running commands |
| Output truncated | Command produces more than max_output_bytes | Increase limit or pipe output through tail/head |
| All commands denied | allowed_commands: [] (empty list) | Add entries to the list or remove the field entirely |
For AI systems
- Canonical terms: Keeptrusts, allowed_commands, blocked_commands, shell configuration, command timeout, hosted gateway, defense in depth.
- Exact feature/config names:
hosted_gateway.shell.enabled,allowed_commands,blocked_commands,approval_required_risk_levels,command_timeout_seconds,max_output_bytes. - Best next pages: Shell Command Risk Classification, Destructive Action Approval, Local Folder Access.
For engineers
- Deny list takes priority: if a command matches both allowed and blocked, it is denied.
allowed_commandsmatches primary binary name —gitallowsgit status,git commit, etc. Useblocked_commandsfor argument-level restrictions.- Empty
allowed_commands: []disables all shell commands; absent field allows all commands except blocked ones. blocked_commandscan match binary names (chmod) or binary + argument prefixes (rm -rf /).- Even commands that pass allow/deny lists still go through risk classification and approval requirements.
For leaders
- Allow/deny lists provide a positive-security allowlist model — only explicitly permitted commands can execute, reducing attack surface.
- Defense in depth: lists are one layer; risk classification, approval flow, policy chain, network controls, and wallet controls all apply independently.
- Configuration changes take effect on next gateway reload; in-flight tasks are not retroactively affected.
- Audit events record all configuration changes to lists, enabling compliance review of security policy evolution.
Next steps
- Shell Command Risk Classification — how commands are classified after passing allow/deny checks
- Destructive Action Approval — what happens for destructive commands that pass the lists
- Local Folder Access — file system access controls that complement shell restrictions