# zeptoclaw has Shell allowlist-blocklist bypass via command/argument injection and file name wildcards

zeptoclaw's shell allowlist/blocklist only checks the first token, so `;`, `$()`, argument injection and filename wildcards bypass Strict mode to run arbitrary commands.

- Payout: Research
- Severity: critical
- Program: zeptoclaw
- Found by: zpbrent
- Disclosed: 2026-03-05
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-5wp8-q9mx-8jx8
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-5wp8-q9mx-8jx8
- Tags: area:oss domain:oss impact:rce kind:research platform:ghsa sev:critical tech:rust technique:source-review vuln:command-injection vuln:misconfiguration

**Target:** Shell command security validator (src/security/shell.rs)
**Root cause:** Allowlist only inspects the first whitespace token, so chained commands after `;`/`$()` pass; blocklist regexes require `\s+` between command and args (defeated by `-P -c`) and literal patterns miss glob wildcards like `/etc/pass[w]d`.
**Steps:**
1. Configure Strict allowlist with only `git`.
2. Submit `/usr/bin/git status; python -P -c 'import os; os.system("rm -rf /")'; cat /etc/pass[w]d`.
3. Validator extracts first token `git`, passes allowlist; `;` chains arbitrary command; `-P -c` evades `python[23]?\s+-c\s+` regex; `pass[w]d` evades literal `/etc/passwd`.
4. validate_command returns Ok and the full string executes.
**How found:** Code review of shell.rs: noticed allowlist uses only `split_whitespace().next()` (first token), regex blocklist assumes `\s+` separators, and literal blocklist matches exact filenames — each trivially evadable.
**Exploitation:** Any caller passing attacker-influenced command strings to zeptoclaw's shell tool in Strict mode can append `;`-chained commands, use argument injection to dodge regex blocklist, and glob wildcards to read blocked files, achieving arbitrary command execution.
**Insight:** When auditing command allowlists, check whether validation parses the whole command or just the first token; shell metacharacters (`;`, `$()`, `|`) after an allowed binary defeat token-prefix checks. For regex blocklists, test flag reordering and argument injection (`-P -c`) and glob wildcards (`pass[w]d`) against literal path denylists.

## Proof of concept (copied exactly from the original report)

**Rust test proving allowlist bypass via injection**

```
#[test]
    fn test_allowlist_bypass() {
        let config =
            ShellSecurityConfig::new().with_allowlist(vec!["git"], ShellAllowlistMode::Strict);
        assert!(config.validate_command("/usr/bin/git status; python -P -c 'import os; os.system(\"rm -rf /\")'; cat /etc/pass[w]d").is_ok());
    }
```

