CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-XVHF-X56F-2HPP
6.10.10%

OpenClaw: When 'Safe' Binaries Bite Back

Alon Barad
Alon Barad
Software Engineer

Feb 18, 2026·6 min read·8 visits

PoC Available

Executive Summary (TL;DR)

OpenClaw allowed certain 'safe' binaries to run without strict checks, assuming they only processed stdin. However, because commands ran in a shell, attackers could use globbing (`*`) or variables (`$VAR`) to smuggle file arguments past the validator. The fix forces argument quoting.

A deep dive into an Argument Injection vulnerability in OpenClaw's `safeBins` mechanism. By failing to account for shell expansion, the validator allowed attackers to bypass allowlists using wildcards and variables, turning 'harmless' tools like `head` into arbitrary file readers.

The Hook: Safety is an Illusion

In the world of secure execution environments, convenience is the silent killer. OpenClaw, a popular tool-running agent, tried to be helpful. It offered a feature called safeBins—a VIP list for binaries deemed too boring to be dangerous. Tools like jq, head, and wc were given a free pass through the rigorous host exec allowlist checks, under the assumption that they would only ever munch on stdin data piped to them.

The logic seems sound on paper: if a binary is only allowed to process piped data, it can't read your secrets file, right? Wrong. This assumption relies on the idea that the command string you validate is exactly what gets executed. But in the messy reality of Linux systems, there is a middleman: the Shell.

The vulnerability (GHSA-XVHF-X56F-2HPP) is a classic tale of "Validator vs. Executor" desynchronization. The OpenClaw validator looked at a command and saw a harmless asterisk. The shell looked at the same command, saw a wildcard, and helpfully expanded it into the filenames of every secret in the directory. It’s like checking a guest list, seeing "Mr. Key Master", and letting him in, only to realize he brought 50 friends through the side door.

The Flaw: A Failure of Imagination

The root cause lies in src/infra/exec-approvals.ts. When host exec allowlist mode is enabled, OpenClaw typically demands that every executed command matches a strict predefined pattern. However, to reduce friction, the developers added an exemption for safeBins.

The validator's job was to ensure these safe binaries weren't passed any positional arguments (like file paths). It did this by inspecting the command string for tokens that looked like paths. If I tried to run head /etc/shadow, the validator would see /etc/shadow, panic, and block the request. It was looking for literal strings.

Here is where the logic falls apart: The validator failed to account for Shell Expansion. Before head ever wakes up, the shell (sh, bash, etc.) parses the command line. If the command contains metacharacters like * (globbing), ?, or variable references like $HOME, the shell expands them in place.

Because the validator operates on the raw command string, it sees head *. It thinks, "Well, * isn't a path. It doesn't start with /. It doesn't look like a file. Proceed." The validator approves the command. The command is then handed to sh -c. The shell sees *, expands it to id_rsa config.json, and suddenly head is reading your private keys. The validator was checking the map; the shell was driving the car off a cliff.

The Code: The Smoking Gun

Let's look at the fix to understand the break. The patch, applied in commit 77b89719d5b7e271f48b6f49e334a8b991468c3b, introduces a new sanitization layer. The developers realized they couldn't trust the raw input string, so they decided to neuter the shell's ability to expand arguments.

The fix introduces buildSafeShellCommand in src/infra/exec-approvals-analysis.ts. The core logic is a wrapper function that forces every argument to be treated as a string literal:

function shellEscapeSingleArg(value: string): string {
  // Shell-safe across sh/bash/zsh: single-quote everything,
  // escape embedded single quotes.
  const singleQuoteEscape = `'\"' sprays '"' sprays '";
  return `'${value.replace(/'/g, singleQuoteEscape)}'`;
}

Before this patch, the code essentially did this: exec("head " + userArgs)

If userArgs was *, the shell ran head *.

After the patch, the code does: exec("head " + "'" + userArgs + "'")

Now, if userArgs is *, the shell runs head '*'. The shell sees the single quotes and treats the asterisk as a literal character rather than a wildcard. head tries to open a file actually named *, fails (probably), and the security model remains intact.

The Exploit: Smuggling Arguments

Exploiting this is trivially satisfying. We don't need buffer overflows or heap spraying; we just need to speak the shell's language. Assume the target system has OpenClaw running with security=allowlist and safeBins enabled (which includes head by default).

Step 1: Reconnaissance

We need to know where we are. If we can run pwd (or if we can guess based on standard deployment paths), we know the directory context. Let's assume we are in ~/.ssh/ or a config directory.

Step 2: The Bypass

If we try: head id_rsa -> BLOCKED. The validator sees a filename.

Instead, we use globbing: head * -> ALLOWED. The validator sees a symbol.

Or, we use variable expansion to construct paths without using path separators: head $HOME/.ssh/id_rsa -> ALLOWED.

Wait, actually, even simpler: if we just want to read any file, we can abuse the fact that ? matches any single character. head id_rs? -> ALLOWED. The validator might not flag this regex-like pattern, but the shell matches it to id_rsa.

The result? The standard output returns the first 10 lines of every file in the directory, bypassing the allowlist entirely.

The Impact: Data Exfiltration

While this isn't a full Remote Code Execution (RCE) in the traditional sense—you are limited to the binaries in safeBins—the impact is severe for data confidentiality.

In a restricted environment, the "allowlist" is often the only thing standing between a compromised sub-process and the keys to the kingdom. By abusing head, tail, or jq, an attacker can read configuration files, private keys, or environment variables (via /proc/self/environ if the OS allows and globbing finds it).

If the safeBins list had been more aggressive—containing a tool that allows file writing or arbitrary execution (like awk or sed with specific flags)—this could easily escalate to full system compromise. As it stands, it is a high-severity information disclosure vulnerability that renders the "allowlist" feature effectively useless for these binaries.

The Fix: Quote Your Inputs

The mitigation is straightforward: Update to version 2026.2.14.

If you are stuck on an older version, you have two options:

  1. Disable safeBins: Remove all entries from tools.exec.safeBins. This forces every command to go through the strict allowlist, which is annoying but secure.
  2. Disable Host Exec Allowlist: If you aren't using the allowlist feature, you aren't vulnerable to its bypass (though you have other problems).

For developers reading this: This is a lesson in Input Sanitization. Never pass user-controlled input to a shell without escaping it. Better yet, avoid the shell entirely. Use execFile (Node.js) or execve (C/Linux) which passes arguments as an array of strings, bypassing the shell's expansion logic completely. If you must use a shell, quote everything. Twice.

Official Patches

GitHubOfficial patch commit

Fix Analysis (1)

Technical Appendix

CVSS Score
6.1/ 10
EPSS Probability
0.10%
Top 100% most exploited

Affected Systems

openclaw < v2026.2.14

Affected Versions Detail

Product
Affected Versions
Fixed Version
openclaw
OpenClaw
< 2026.2.14v2026.2.14
AttributeDetail
Attack VectorArgument Injection
ImpactInformation Disclosure / File Read
Affected Componenttools.exec.safeBins validator
CVE IDGHSA-XVHF-X56F-2HPP
Fixed Versionv2026.2.14
Fix Commit77b89719d5b7e271f48b6f49e334a8b991468c3b

MITRE ATT&CK Mapping

T1059Command and Scripting Interpreter
Execution
T1559Inter-Process Communication
Execution
T1005Data from Local System
Collection

Vulnerability Timeline

Vulnerability reported
2026-01-26
Patch developed and released in v2026.2.14
2026-02-14
GHSA advisory published
2026-02-16