command-guard

View source on GitHub

Deterministic regex-based command blocker for exec/bash tool calls. Blocks destructive commands (rm -rf, fork bombs, force push, etc.) before execution. Companion to content-guard and channel-guard — command-guard protects the shell execution surface.

How it works

Hooks into before_tool_call for exec and bash tools:

  1. Strips single-quoted string contents (bash literals are safe — echo 'rm -rf /' is harmless)
  2. Matches the full command against compiled regex patterns (catches patterns spanning delimiters like fork bombs)
  3. Splits on &&, ||, ; and matches each segment
  4. For pipe-to-shell patterns, checks pipe targets against a safe list before blocking
  5. On match: returns { block: true, blockReason } to prevent execution

No ML model, no network calls, no heavy dependencies. Runs in <5ms.

Pattern categories

CategoryExamplesCount
destructiverm -rf, sudo rm2
system_damageFork bombs, chmod 777, dd of=/dev/, mkfs., > /dev/sd5
pipe_to_shellcurl url | sh, wget url | bash1
git_destructive--force push, reset --hard, branch -D, --global config write, rebase --skip, clean -f6
interpreter_escapebash -c, eval, python3 -c, node -e3

Install

cd extensions/command-guard
npm install

No model download — the plugin has zero runtime dependencies.

Configuration

Add to your openclaw.json:

{
  plugins: {
    entries: {
      "command-guard": {
        enabled: true,
        config: {
          guardedTools: ["exec", "bash"],
          failOpen: false,
          logBlocks: true
        }
      }
    }
  }
}

Config reference

OptionTypeDefaultDescription
guardedToolsstring[]["exec", "bash"]Tool names to intercept
failOpenbooleanfalseAllow commands when config unavailable
logBlocksbooleantrueLog blocked commands to gateway console

Customizing patterns

Edit blocked-commands.json in the plugin directory. Each entry:

{
  "regex": "\\brm\\s+-rf\\b",
  "message": "Recursive force delete blocked.",
  "category": "destructive"
}

Patterns use JavaScript regex syntax. The plugin compiles them once at startup. If the config file is missing or malformed, hardcoded fallback patterns are used (fail-closed).

Safe pipe targets

The safe_pipe_targets list prevents false positives on commands like curl url | jq .:

jq, grep, sort, wc, head, tail, less, cat, tee, tr, uniq

Excluded: xargs, sed, awk — these can execute arbitrary commands or write files, so they are not considered safe pipe targets.

A pipe-to-shell match is only blocked if at least one pipe target is not in the safe list. A chain like curl url | transform | sh is still blocked because sh is not safe.

Guard plugin comparison

channel-guardcontent-guardfile-guardnetwork-guardcommand-guard
Hookmessage_receivedbefore_tool_callbefore_tool_callbefore_tool_callbefore_tool_call
ProtectsInbound channel messagesInter-agent boundaryFile systemNetwork accessShell execution
MethodLLM via OpenRouterLLM via OpenRouterDeterministic patternsDeterministic regex + globRegex patterns
DependenciesOpenRouter API keyOpenRouter API keyNoneNoneNone
Latency~100-500ms~500ms-2s<10ms<5ms<5ms

Testing

cd extensions/command-guard && npm test

All tests run in <1s (no model download).

Limitations

  • Regex bypass — obfuscation via variables ($CMD), base64 encoding, or hex escapes can bypass pattern matching. Command-guard is a defense-in-depth layer, not a complete solution.
  • Heredocs and process substitution — the command splitter handles &&, ||, ; but does not parse heredocs (<<EOF), newlines within strings, or process substitution (<()) correctly.
  • Double-quoted strings — only single-quoted strings are stripped. Double-quoted strings allow variable expansion and are still checked (correctly, since they can contain executable content).
  • Best-effort interpreter detectionbash -c, eval, python3 -c etc. are caught, but deeply nested or indirect invocations are not.
  • Not a sandbox — command-guard blocks known dangerous patterns but does not provide process isolation. Use Docker sandboxing (Phase 3 ) for defense-in-depth.
Last updated on