Mar 5, 2026·7 min read·18 visits
A blocklist bypass in zeptoclaw's Android shell tool allows execution of banned commands like 'rm -rf' via argument splitting (e.g., 'rm -r -f').
The `zeptoclaw` Rust framework contains a security bypass vulnerability in its Android device shell interface (`device_shell`). The vulnerability allows attackers to execute dangerous commands, specifically recursive file deletions (`rm -rf`), by circumventing a naive blocklist implementation. The original security control relied on literal substring matching, which fails to account for argument permutations, alternative flag syntax, or binary aliasing (e.g., `busybox rm`). This flaw permits malicious agents or attackers with access to the framework's shell tool to perform destructive actions on connected Android devices.
The zeptoclaw package functions as an AI agent framework, providing various tools for interacting with external systems. One such tool, device_shell, facilitates the execution of shell commands on connected Android devices via the Android Debug Bridge (ADB). To prevent accidental or malicious data loss, the developers implemented a blocklist intended to intercept and reject dangerous commands, most notably recursive force deletion (rm -rf).
The vulnerability resides in the implementation of this blocklist. Instead of parsing the command arguments to understand the intent, the system performed a simple literal string search. It checked if the command string contained specific banned substrings such as "rm -rf" or "rm -r". This approach is fundamentally flawed when applied to command-line interfaces, where the same operation can be invoked using a multitude of syntactically different but semantically equivalent command structures.
By crafting commands that avoid the exact blocked substrings while retaining the destructive flags, an attacker can bypass the filter entirely. This allows the execution of arbitrary removal commands on the target Android file system, potentially leading to critical data loss or device bricking.
The root cause of this vulnerability is an Incomplete List of Disallowed Inputs (CWE-184) combined with Improper Neutralization of Argument Delimiters (CWE-88). The security logic relied on a "deny-list" approach using naive string matching, which is insufficient for complex grammars like POSIX shell commands.
In standard Unix-like shells (including Android's mksh or toybox shell), command arguments are tokenized based on whitespace. Flags can often be combined (bundled), separated, or reordered without changing the program's behavior. For example, the rm binary accepts flags in any order relative to the target path. The vulnerable code in zeptoclaw failed to model this behavior.
Technical Flaws:
"rm -rf". It did not detect rm invoked with separated flags (e.g., rm -r -f).busybox rm or toybox rm, which effectively execute the same logic but change the command string signature./system/bin/rm instead of just rm would bypass a filter looking for the latter if not anchored correctly.The following analysis compares the vulnerable implementation with the patched logic introduced in commit 68916c3e4f3af107f11940b27854fc7ef517058b. The original code relied on a simple iterator over a static array of banned strings.
Vulnerable Implementation (Pre-Patch):
// src/tools/android/actions.rs
// Naive check uses .contains() on the raw command string
let blocked = [
"rm -rf",
"rm -r",
// ... other patterns
];
for pattern in &blocked {
// If the command is "rm -r -f /", this check fails
// because the string "rm -rf" is not present literally.
if lower.contains(pattern) {
return Err(ZeptoError::Tool(format!("Blocked dangerous command...")));
}
}Patched Implementation (Fixed):
The fix introduces a robust parsing strategy. It tokenizes the input string and inspects the arguments semantic meaning rather than their string representation. The new logic specifically looks for the rm binary (or its aliases) and then iterates through all arguments to detect if both recursive and force flags are present in any combination.
// src/tools/android/actions.rs
// 1. Tokenize the input command
let tokens: Vec<&str> = command.split_whitespace().collect();
// 2. Identify if the binary is 'rm', '/system/bin/rm', 'busybox rm', etc.
if let Some(rm_args) = rm_invocation_args(&tokens) {
let mut has_r = false;
let mut has_f = false;
// 3. Iterate through all arguments to find dangerous flags
for &tok in rm_args {
if tok == "--recursive" { has_r = true; }
else if tok == "--force" { has_f = true; }
// Handle combined flags like '-rf', '-fr', '-vfr', etc.
else if tok.starts_with('-') && !tok.starts_with("--") {
let flags = &tok[1..];
if flags.contains('r') { has_r = true; }
if flags.contains('f') { has_f = true; }
}
}
// 4. Block only if both flags are present
if has_r && has_f {
return Err(ZeptoError::Tool("Recursive force deletion is blocked".into()));
}
}This approach correctly identifies rm -r -f, rm -fr, and rm --recursive --force as semantically identical dangerous commands.
An attacker can exploit this vulnerability by submitting specific command strings to the device_shell tool. The goal is to construct a command that instructs the underlying shell to perform a recursive deletion while ensuring the command string does not strictly match the blocked patterns.
Bypass Vectors:
Flag Splitting:
rm -rf /sdcardrm -r -f /sdcard-rf. By separating the flags with a space, the substring check fails, but the rm binary still interprets both flags.Flag Reordering:
rm -f -r /sdcard-r followed by -f.Long Flags:
rm --recursive --force /sdcard-rf), the verbose GNU/POSIX standard flags will bypass detection.Binary Aliasing:
busybox rm -rf /sdcardrm, invoking it via busybox (common on Android) changes the command signature, evading detection.Proof of Concept:
The following Rust test case, adapted from the patch, demonstrates the successful detection of previously allowed commands:
#[tokio::test]
async fn test_bypass_permutations() {
// These commands previously executed successfully
let payloads = [
"rm -r -f /sdcard",
"rm --recursive --force /sdcard",
"/system/bin/rm -fr /data/local/tmp",
"busybox rm -rf /sdcard"
];
for cmd in payloads {
// In the patched version, these now return errors
assert!(device_shell(&adb, cmd).await.is_err());
}
}The impact of this vulnerability is categorized as High. It allows for the circumvention of safety guardrails designed to prevent catastrophic data loss on connected hardware.
Operational Impact:
/sdcard) or, if the device is rooted, the system partition (/system, /data). This effectively factory resets or "bricks" the device, requiring manual recovery or reflashing.Scope:
This affects any deployment of the zeptoclaw framework where untrusted agents or users can supply commands to the device_shell interface. It is particularly critical for automated testing environments or agentic workflows where the AI might hallucinate or be tricked into generating destructive commands.
The vulnerability is addressed in zeptoclaw by moving from string-matching to semantic argument parsing. Users and developers using this crate must upgrade to the patched version immediately.
Remediation Steps:
zeptoclaw to the version containing commit 68916c3e4f3af107f11940b27854fc7ef517058b (typically v1.1.0 or later).device_shell implementation includes the is_rm_recursive_force check or equivalent token-based validation.Defense-in-Depth:
While the patch fixes the specific rm -rf bypass, developers should consider additional layers of security for shell execution:
root unless strictly required.| Product | Affected Versions | Fixed Version |
|---|---|---|
zeptoclaw qhkm | < 1.1.0 | 1.1.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-184 (Incomplete List of Disallowed Inputs) |
| Attack Vector | Local / Remote (via Agent Interface) |
| Severity | High |
| Exploit Status | Functional PoC |
| Affected Component | device_shell() function |
| Patch Commit | 68916c3e4f3af107f11940b27854fc7ef517058b |
A critical stored Cross-Site Scripting (XSS) vulnerability was identified in Froxlor server administration software panel before version 2.3.8. Authenticated customers with DNS editor privileges can inject malicious JavaScript into DNS TXT records. Because the application processes these values via a raw formatting callback without context-aware HTML entity encoding, the payload executes in the security context of administrative users who view the affected domain's DNS zones.
An authenticated administrator with privileges to manage admin accounts (such as change_serversettings) can execute arbitrary SQL commands via a second-order SQL injection vulnerability. The flaw resides in Froxlor's administrative API endpoints, specifically during the handling of IP address mapping parameters which are stored as serialized arrays and later interpolated without sanitization into active database queries. This vulnerability allows high-privileged administrative attackers to compromise the database. By injecting a payload into administrative profile metadata, an attacker can extract sensitive credentials, manipulate backend settings, or potentially disrupt database integrity. The vulnerability affects all versions of Froxlor prior to 2.3.8.
CVE-2026-54543 is a DNS Resource Record (RR) Injection vulnerability in Froxlor, an open-source server administration control panel. Prior to version 2.3.8, the DomainZones.add API command failed to perform strict sanitization and validation on the user-controlled record (label) and type parameters before serializing them into BIND-compatible zone files. An authenticated customer with DNS zone management permissions can inject control characters, breaking out of the original record context to define unauthorized resource records within managed zones.
CVE-2026-42533 is a critical security vulnerability discovered in NGINX Open Source, NGINX Plus, NGINX Ingress Controller, and related products, referred to as the 'Two-Pass Capture-Clobbering' bug. The flaw is situated within NGINX's internal evaluation engine when handling complex variables, exposing a heap-based buffer overflow and information leak when a configuration chains regular expression-based map directives with numbered capture groups. An unauthenticated remote attacker can exploit this weakness by transmitting crafted HTTP requests to trigger remote code execution or defeat ASLR.
Froxlor prior to version 2.3.8 contains a high-severity architectural flaw where the standalone lib/ajax.php entry point bypasses the centralized request validation in lib/init.php. Unauthenticated remote attackers can leverage Cross-Site Request Forgery (CSRF) to induce authenticated administrators to submit forged requests that modify API key whitelists and expiration dates, potentially yielding persistent, out-of-band administrative control.
An insecure data retrieval flaw in the Froxlor server administration panel API allows authenticated remote attackers to retrieve unredacted bcrypt password hashes and Base32-encoded Time-Based One-Time Password (TOTP) seeds. Affected endpoints include several 'get' and 'listing' handlers for customers, administrators, and FTP accounts. Utilizing these leaked parameters, attackers can crack the password hashes offline and concurrently generate valid second-factor authentication codes to completely bypass access controls.