Feb 20, 2026·5 min read·3 visits
OpenClaw's `safeBins` feature intended to allow harmless tools to run automatically. However, it failed to block dangerous flags like `sort -o` (write output to file) and `grep -r` (recursive read). This allowed attackers to bypass the 'stdin-only' restriction, leading to Arbitrary File Write and Arbitrary File Read vulnerabilities.
The road to remote code execution is often paved with good intentions and 'safe' lists. OpenClaw, an execution approval system, attempted to reduce user friction by allowing specific 'safe binaries' (like `grep` and `sort`) to run without manual approval, provided they only accepted input from stdin. Unfortunately, the developers underestimated the sheer power of 50-year-old Unix utilities. By failing to account for binary-specific flags that override standard I/O streams, the system allowed attackers to turn a simple text sorter into an arbitrary file writer and a text searcher into a recursive filesystem exfiltrator. This vulnerability highlights the classic security pitfall of blacklisting arguments instead of whitelisting strict behaviors.
In the world of automated agents and execution sandboxes, friction is the enemy. Every time an agent asks, "May I execute this command?", a developer loses their flow. To combat this, OpenClaw introduced a feature called safeBins. The premise was seductive in its simplicity: create a list of tools that are statistically unlikely to destroy a machine—utilities like jq, wc, grep, and sort—and let them run without nagging the user, provided they don't touch the filesystem.
The implementation relied on a heuristic: if the command arguments don't look like file paths, allow it. The logic assumed that if you run sort without a filename, it defaults to reading from stdin and printing to stdout. Perfectly harmless, right? It’s just reordering text.
This is where the "Unix Philosophy" bites back. These tools aren't just pure functions; they are ancient, feature-rich monoliths. The developers forgot that in Unix, almost everything is a file operation if you pass the right flag. By focusing on positional arguments (like sort myfile.txt), they completely missed the optional arguments that fundamentally change the tool's behavior.
The vulnerability lies in src/infra/exec-approvals-allowlist.ts. The enforcement logic, isSafeBinUsage, scanned the command string looking for things that resembled paths. It was a valiant attempt at input sanitization, but it suffered from a fatal blind spot: it treated flags as opaque tokens rather than instructions.
Consider the sort command. In its default state, it sorts lines from standard input. But sort has an -o flag (or --output). When you run sort -o /tmp/pwn.sh, you aren't just sorting; you are writing the result to a specific file, bypassing stdout entirely. Since the validator didn't blacklist the -o flag, the path following it was just seen as a string argument, or worse, if attached like -o/tmp/file, it might not have been parsed as a path at all depending on the tokenizer.
Similarly, grep is designed to search text. But grep -r (recursive) or grep -R tells it to ignore the fact that you didn't provide a file path and instead devour the entire directory tree. The validator was looking for a specific pattern of abuse—accessing a specific file via a positional argument—while the attacker just changed the mode of operation entirely.
Let's look at how a researcher (specifically nedlir, who found this) turns a text processing tool into a weapon. The goal is to bypass the execution approval prompt. If we can write to a file without approval, we win.
Scenario 1: The sort Bypass (Arbitrary File Write)
The sort command allows us to write data to a file using the -o flag. An attacker can pipe a malicious script into sort, and sort will dutifully write that script to disk, effectively creating an executable file where none should exist.
# The system sees: "sort" (Safe Bin) with some arguments.
# The system checks: Are there positional file paths? No.
# The result: Approval bypassed.
# The Payload:
sort -o /home/user/.bashrc <<EOF
echo "pwned by openclaw" >> /tmp/hacked
EOFScenario 2: The grep Bypass (Information Disclosure)
Maybe we don't want to write; maybe we want to steal secrets. grep is normally safe because it filters input. But grep -r searches the filesystem. If the agent is running in a directory containing .env files or source code, we can read it all without specifying a single file path.
# Recursively search for "KEY" in the current directory
grep -r "SECRET_KEY" .The validator allowed this because . was likely not flagged as a dangerous path, or the recursive flag r was simply ignored.
The patch, authored by Peter Steinberger in commit cfe8457, takes a scorched-earth approach to the problem. Realizing that parsing command line arguments correctly is difficult, the team decided to explicitly blacklist dangerous flags for specific binaries.
They introduced a SAFE_BIN_OPTION_POLICIES map. This map acts as a second layer of defense. If a binary is in the safe list, it is now cross-referenced against this policy map.
// From the patch:
const SAFE_BIN_OPTION_POLICIES: Record<string, string[]> = {
sort: ['-o', '--output'],
grep: ['-r', '--recursive', '-d', '--directories', '--dereference-recursive'],
};Furthermore, the patch hardened the parsing logic to handle sticky flags (like -ofile) and, most critically, removed sort and grep from the default safe list entirely. They are now opt-in. This is the correct move: "secure by default" means not assuming 50-year-old C programs are safe for unsupervised execution.
This vulnerability serves as a stark reminder of the "Allowlist vs. Blocklist" debate. The OpenClaw team tried to block specific behaviors (file paths) while allowing the tool generally. This is a blocklist approach, and it almost always fails because the attack surface of a binary like grep is vast and documented in man pages that are older than most developers.
The only truly safe way to execute commands without approval is to allowlist the entire command string (e.g., grep "foo" is safe, grep * is not), or to run the binary in a strictly confined sandbox (like a container) where file system access is physically impossible at the kernel level. Relying on regex to parse CLI flags is like trying to parse HTML with regex: you summon the chaos.
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
openclaw openclaw | < 0.1.18 | 0.1.18 |
| Attribute | Detail |
|---|---|
| Component | openclaw/safeBins |
| Attack Vector | Local / Agent Command Injection |
| Vulnerability Type | Argument Injection / Logic Flaw |
| CVSS | 4.3 (Medium) |
| Impact | Arbitrary File Read/Write |
| Exploit Status | PoC Available |