feat(security): RubberBand - static command pattern detection for exec pipeline#8023
feat(security): RubberBand - static command pattern detection for exec pipeline#8023jeffaf wants to merge 8 commits intoopenclaw:mainfrom
Conversation
70ed9f4 to
e942f01
Compare
ffc483e to
3c1da6e
Compare
53160fc to
183532f
Compare
bfc1ccb to
f92900f
Compare
183532f to
85ab5d1
Compare
Adds RubberBand, a static analysis layer that catches dangerous command patterns before execution. Designed to detect prompt injection attacks that trick the agent into running malicious commands. Key features: - Pattern-based detection for credential access, exfiltration, reverse shells, persistence, config tampering, and more - Normalization layer catches encoding bypasses (Unicode, hex, octal, URL encoding, shell escapes) - Context-aware preprocessing reduces false positives (git commit messages, echo statements) - Score stacking across categories for compound threats - Configurable thresholds and modes (block/alert/log/shadow) - Cross-platform patterns for Unix, macOS, and Windows Configuration: - tools.exec.rubberband.enabled: true/false - tools.exec.rubberband.mode: block|alert|log|shadow|off - tools.exec.rubberband.notifyChannel: alert user on block Patterns use [^;|&\n]* to prevent matching across command separators, avoiding false positives on legitimate commands like: cat file 2>/dev/null || cat other/file.md
The system/prompt pattern was matching any command containing echo/cat/printf with the words 'system' and 'prompt' anywhere in the line. This caused false positives when posting GitHub comments or other API calls that discussed prompt injection in their body text. Now requires a redirect (>) between the command and the system/prompt path, consistent with the other patterns in the same rule group.
Heredoc writes (cat >> file << EOF) were triggering false positives for config_tampering and agent_memory_tampering because the heredoc body contained keywords like AGENTS.md, SOUL.md, MEMORY.md. Fix: detect heredoc syntax (<< DELIM) in stripContextSafeContent and treat the entire command as a safe data write operation. Heredocs piped to interpreters (cat << EOF | bash) are still flagged. Added rubberband.test.ts with 10 test cases covering: - Heredoc false positive (the triggering case) - Heredoc to memory files - Malicious heredoc piped to bash (still caught) - Direct redirects without heredoc (still caught) - Context-safe stripping (git commit, echo) - Real threats (SSH keys, reverse shells, cred dumps, config tampering)
Add negative lookahead to prevent false positives when agent operates on files within its own workspace directory. Actual config paths outside workspace/ are still protected. 14 tests passing (4 new workspace exclusion tests).
Deduplicate RubberBand BLOCK/ALERT handling from three inline blocks into a single runRubberBandCheck() helper in security/rubberband.ts. Reduces bash-tools.exec.ts by ~63 lines.
Reset schema.ts to match upstream (removes 798 lines of duplicated code from rebase conflict resolution). RubberBand field labels and descriptions now live in schema.hints.ts where upstream refactored all config UI metadata.
85ab5d1 to
56975bf
Compare
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
26 similar comments
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
|
Closing this PR because it looks dirty (too many unrelated commits). Please recreate the PR from a clean branch. |
Summary
Adds a lightweight static detection layer to the exec pipeline that catches dangerous commands (credential access, exfiltration, reverse shells, persistence) as defense-in-depth against prompt injection.
RFC Discussion: #4981
What it does
Pre-exec hook that analyzes commands before execution:
Key differentiators
This PR improves on prior approaches (Shield-Shell #4684, #7604 proposal) with:
Performance
~0.005ms overhead per command (effectively invisible vs 10-50ms exec spawn time).
Configuration
Related work
AI Disclosure
Developed with Claude (Opus 4.5) running in OpenClaw. Fully tested on live fork. I understand the code and can answer questions.
🦞 Like the bands on lobster claws — keeps the agent from pinching the operator.