Mar 5, 2026·6 min read·3 visits
Zeptoclaw fails to properly sanitize shell commands, allowing attackers to bypass security allowlists using metacharacters (e.g., `;`, `|`), globbing (e.g., `pass[w]d`), and flag permutations. This results in Critical Remote Code Execution (RCE).
A critical vulnerability in the `zeptoclaw` AI agent runtime allows attackers to bypass shell security controls, including allowlists and blocklists, to execute arbitrary commands. The flaw stems from insufficient input validation in `src/security/shell.rs`, specifically regarding shell metacharacters, globbing patterns, and argument permutation. By manipulating command strings, an attacker can escape the intended sandbox and execute code on the host system, even when 'Strict' security modes are enabled.
The zeptoclaw package, a lightweight AI agent runtime written in Rust, implements a security layer designed to restrict the shell commands an agent can execute. This layer relies on allowlists (permitted commands) and blocklists (forbidden patterns) to sandbox the AI's capabilities. GHSA-5WP8-Q9MX-8JX8 represents a catastrophic failure of this sandbox, where multiple logic errors and naive string parsing techniques combine to render the security controls ineffective.
The vulnerability affects the src/security/shell.rs component, specifically the validate_command function. This function is responsible for intercepting command execution requests and verifying them against the configured security policy. The failure to account for shell grammar—specifically command chaining, subshells, and wildcard expansion—allows malicious inputs to pass validation while executing unauthorized payloads.
This issue is particularly severe because it defeats the primary safety mechanism intended to prevent AI agents from performing destructive actions. An attacker with the ability to influence the agent's command generation, or an agent that hallucinates malicious commands, can achieve full Remote Code Execution (RCE) on the host system, bypassing restrictions intended to limit scope to benign operations like git status or ls.
The vulnerability stems from four distinct implementation flaws within the command validation logic. Each flaw represents a specific failure to understand or parse the complexity of Unix shell command syntax.
1. Naive Tokenization & Command Chaining
The validator enforced allowlists by checking only the first token of a space-delimited string. It failed to detect shell metacharacters that delimit separate commands, such as semicolons (;), pipes (|), or logical operators (&&, ||). Consequently, a command starting with an allowed binary (e.g., git) could be followed by a separator and an arbitrary malicious command. The parser validated git, approved the string, and passed the entire payload to the shell for execution.
2. Incomplete Regex Anchoring
Blocklists for interpreters like Python relied on rigid regular expressions (e.g., python[23]?\s+-c). These patterns assumed a standard argument order. By injecting intermediate flags that do not alter the execution flow but disrupt the regex match (e.g., python3 -P -c), attackers could execute arbitrary scripts. The regex failed to account for the flexibility of command-line argument parsing.
3. Globbing vs. Literal Matching
The security module maintained a list of sensitive file paths (e.g., /etc/passwd) to prevent read access. However, this check performed a literal string comparison. It did not resolve shell wildcards (globbing). An attacker could request cat /etc/pass[w]d, which does not string-match /etc/passwd but expands to the same path during shell execution, bypassing the blocklist entirely.
4. Fail-Open Logic in Strict Mode
A critical logic error existed in the 'Strict' mode enforcement. The code contained a guard clause: if !self.allowlist.is_empty(). This was intended to skip validation only if no allowlist was defined (implying a default-allow state). However, in Strict mode, an empty allowlist should imply deny all. Instead, this check caused the validator to skip all checks when the allowlist was empty, effectively defaulting to 'allow all' when it should have been most restrictive.
The following analysis illustrates the defective logic in src/security/shell.rs and the subsequent remediation applied in commit 68916c3e. The original code relied on simplistic string operations that were insufficient for security boundaries.
Vulnerable Logic (Simplified Representation)
// OLD: Naive validation susceptible to bypass
pub fn validate_command(&self, cmd: &str) -> Result<(), SecurityError> {
// FLAW 1: Logic error makes empty allowlist fail-open
if !self.allowlist.is_empty() {
let first_token = cmd.split_whitespace().next().unwrap_or("");
if !self.allowlist.contains(first_token) {
return Err(SecurityError::NotAllowed);
}
}
// FLAW 2: Literal check fails against globs (e.g. /etc/pass[w]d)
for sensitive in &self.blocked_files {
if cmd.contains(sensitive) {
return Err(SecurityError::AccessDenied);
}
}
Ok(())
}Patched Logic
The fix introduces strict metacharacter detection, regex hardening, and 'deglobbing' heuristics. The validate_command function now preemptively rejects inputs containing shell operators before checking the allowlist.
// NEW: Hardened validation logic
pub fn validate_command(&self, cmd: &str) -> Result<(), SecurityError> {
// FIX 1: Block command chaining characters explicitly
let dangerous_chars = [';', '|', '&', '`', '$', '\n'];
if cmd.chars().any(|c| dangerous_chars.contains(&c)) {
return Err(SecurityError::MetacharacterDetected);
}
// FIX 2: Deglobbing to catch obfuscated paths
let expanded_cmd = self.expand_globs(cmd); // Heuristic expansion
for sensitive in &self.blocked_files {
if expanded_cmd.contains(sensitive) {
return Err(SecurityError::AccessDenied);
}
}
// FIX 3: Robust regex for interpreters
// Pattern updated to: python[23]?\s+.*-[A-Za-z]*c[\s=]
if self.interpreters_regex.is_match(cmd) {
return Err(SecurityError::InterpreterDetected);
}
Ok(())
}> [!NOTE]
> The patch also addresses the rm command specifically in src/tools/android/actions.rs, preventing flag permutation attacks like rm -r -f where the recursive flag was previously only detected if it was the first argument.
Exploiting this vulnerability requires the attacker to supply a command string to the zeptoclaw runtime. This typically occurs via an AI agent's tool execution capability. The following Proof-of-Concept (PoC) vectors demonstrate the specific bypass techniques.
Vector 1: Command Chaining (Allowlist Bypass)
If git is on the allowlist, the attacker appends a semicolon to execute a second, unauthorized command.
# 'git' satisfies the allowlist check; shell executes both.
git status; python3 -c 'import os; os.system("id")'Vector 2: Argument Injection (Regex Bypass)
The blocklist attempts to stop python -c but fails to account for argument permutation or combined flags.
# '-P' flag breaks the specific regex sequence 'python -c'
python3 -P -c 'import os; os.system("cat /etc/shadow")'Vector 3: Globbing Obfuscation Attackers use wildcard characters to bypass literal string matching for sensitive files.
# Literal match for "/etc/passwd" fails; shell expands it to the target file.
cat /etc/pass[w]dVector 4: Subshell Injection Using command substitution allows execution of arbitrary commands as arguments to an allowed command.
# The $(...) is evaluated by the shell before 'git' runs.
git status $(touch /tmp/pwned)The successful exploitation of GHSA-5WP8-Q9MX-8JX8 results in Critical impact to the confidentiality, integrity, and availability of the host system. Because zeptoclaw acts as an execution engine for AI agents, bypassing its sandbox grants the agent (and by extension, the prompter or controller) the privileges of the user running the runtime.
Confidentiality: Attackers can read any file accessible to the user, including SSH keys, cloud credentials (e.g., ~/.aws/credentials), and source code. The globbing bypass specifically targets file access blocklists.
Integrity: Attackers can modify files, inject backdoors into local repositories, or alter the behavior of the AI agent itself. The ability to execute arbitrary commands allows for persistence mechanisms to be installed.
Availability: Malicious commands like rm -rf / (demonstrated in the Android tool vector) or fork bombs can cause immediate denial of service or data loss.
CVSS Vector (Estimated): CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (9.8). The attack vector is likely network-based (via API or prompt injection), requires no privileges if the agent is public-facing, and has no user interaction requirements.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
zeptoclaw qhkm | <= 0.6.2 | Commit 68916c3e |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-78 (OS Command Injection) |
| Attack Vector | Remote (via Prompt/API) |
| CVSS Score | 9.8 (Critical) |
| Impact | Arbitrary Code Execution |
| Exploit Status | PoC Available |
| Fix Commit | 68916c3e |
Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')