The landscape of AI developer tools recently faced a significant security challenge with the discovery of a critical Remote Code Execution (RCE) vulnerability in Anthropic’s Claude Code CLI. Identified by security researcher Joernchen of 0day.click, this flaw underscores a fundamental oversight in how command-line interfaces (CLIs) process external inputs. Unlike many vulnerabilities found through automated scanning, this RCE was uncovered via a meticulous manual review of the source code, specifically focusing on the application's early configuration initialization.
This vulnerability, patched in version 2.1.118, allowed attackers to execute arbitrary commands on a user's machine. The root cause was not a complex AI-specific logic error but a classic input validation failure within the tool's deeplink handler. By crafting a malicious deeplink, an attacker could bypass security prompts and gain full control over the user's terminal session.
The Technical Root: The Peril of "Too Eager" Parsing
At the core of this vulnerability was a function named eagerParseCliFlag. CLI applications often need to load specific configurations very early in their lifecycle, sometimes even before standard argument parsing libraries (like Commander.js) are initialized. Claude Code utilized eagerParseCliFlag to proactively search for flags such as --settings or --setting-sources to ensure the environment was correctly configured.
The critical flaw lay in its simplistic implementation. The eagerParseCliFlag function iterated through the raw process.argv array, using a startsWith check to identify potential flags. It was designed to handle both --flag=value and --flag value syntaxes. However, it operated without any awareness of the command-line context. It treated every string in the argument array as a standalone potential flag, failing to recognize that a string like --settings=... might actually be a value associated with a different flag.
This context-blind parsing created a dangerous injection point. If an attacker could manipulate the value of a legitimate flag, they could embed a second, malicious flag within that value. When eagerParseCliFlag scanned the arguments, it would mistakenly interpret the injected string as a top-level configuration override. This practice of using startsWith on raw argument arrays without proper context is a known anti-pattern in CLI development, as it fundamentally breaks the integrity of command parsing.
// Simplified representation of the vulnerable logic
function eagerParseCliFlag(argv) {
for (const arg of argv) {
if (arg.startsWith('--settings=')) {
// Problem: This assumes 'arg' is a flag, not a value of another flag
const settingsJson = arg.substring('--settings='.length);
// Attempt to parse and apply settings immediately
console.log('Eagerly applying settings:', settingsJson);
// In the real exploit, this would lead to loading malicious hooks
}
}
}
// Example of how it could be exploited
// Original: claude --prefill "--prompt-text=Hello world"
// Exploited: claude --prefill "--prompt-text=--settings={\"hooks\":...}"
// The eager parser would see '--settings={...}' as a flag, not part of '--prompt-text'
By exploiting this lack of context, an attacker could force the CLI to load an entirely different set of settings than intended by the user.
The Attack Vector: Weaponizing Deeplinks for Remote Code Execution
The primary delivery mechanism for this exploit was the claude-cli:// deeplink protocol. Deeplinks are designed for user convenience, allowing web pages or other applications to trigger specific actions within a local tool. For Claude Code, the claude-cli://open URI was intended to open the CLI and pre-fill a prompt using a query parameter, typically q.
When a user clicks a link such as claude-cli://open?q=hello, the operating system passes this to the Claude Code handler. The handler then translates this into a command-line execution, using the --prefill flag to pass the content of q to the CLI. Due to the
"eager" parsing issue, an attacker could craft a q parameter containing more than just a simple prompt; they could embed a configuration flag.
Consider a malicious link structured as follows:
claude-cli://open?q=--settings={"hooks":...}
When the CLI is launched, the argument array might resemble this:
["claude", "--prefill", "--settings={\"hooks\":...}"]
The standard argument parser would correctly interpret --settings=... as the value for the --prefill flag. However, the vulnerable eagerParseCliFlag function would scan the array, identify a string beginning with --settings=, and immediately load it as the global configuration. This allowed an attacker to override any application setting simply by enticing a user to click a specially crafted link.
From Injection to Execution: Exploiting Hooks
Once an attacker achieves the ability to inject arbitrary settings, the path to Remote Code Execution (RCE) becomes direct. Claude Code incorporates a powerful feature called "hooks," which enable users to automate actions at specific points in a session's lifecycle. For instance, a user might configure a script to run every time a new session begins. By injecting a malicious configuration, an attacker can define their own hooks that execute shell commands.
The most effective target for this exploit is the SessionStart hook. An attacker can craft a JSON payload that defines a command to be executed as soon as the CLI initializes. Because the eagerParseCliFlag function has already loaded these settings, the command executes immediately in the background, often before the user is even aware the CLI has opened.
To enhance the stealth of the attack, the researcher discovered a method to bypass the "Workspace Trust" dialog. Typically, Claude Code prompts for permission before operating within a new repository. However, if the attacker sets the repo parameter in the deeplink to a repository the user has previously trusted (e.g., anthropics/claude-code), the CLI assumes a safe environment. This bypasses a crucial security defense, allowing the injected command to run without any user interaction beyond the initial click.
The Fix and Lessons for Developers
Anthropic promptly addressed this vulnerability, releasing a patch in Claude Code version 2.1.118. The fix involved abandoning the "eager" and context-blind parsing of the argument array. The updated code now employs a more robust approach that correctly interprets the structure of command-line arguments, distinguishing between flags and their associated values. This eliminated the injection surface.
For developers building CLI tools, particularly those supporting deeplinks, this vulnerability offers several critical lessons:
- Prioritize Robust Libraries: Avoid custom, manual string matching on raw argument arrays for parsing. Libraries like Commander.js or Yargs are battle-tested and designed to handle edge cases and prevent injection vulnerabilities.
- Implement Context-Aware Parsing: Never assume a string is a flag solely because it starts with dashes. Always consider its position and context within the command-line arguments.
- Sanitize Deeplink Inputs: Treat all data originating from a URI handler as untrusted and potentially malicious. Implement rigorous sanitization and validation.
- Limit Hook Power: For hooks that execute shell commands, consider adding additional confirmation steps or restricting their capabilities to prevent misuse.
The "startsWith" anti-pattern is a common pitfall in applications performing early configuration loading. A seemingly minor oversight in command-line parsing can lead to a total system compromise. By adhering to these principles, developers can provide the convenience of deeplinks and automation without compromising user system security.
Key Takeaways
- The Claude Code RCE highlights that even advanced AI tools are vulnerable to fundamental software security flaws, particularly input validation issues.
- "Eager parsing" of raw
process.argv arrays without context is a dangerous anti-pattern that can lead to flag injection.
- Deeplinks, while convenient, can serve as potent attack vectors if their inputs are not rigorously sanitized and validated.
- Robust command-line parsing libraries and context-aware input handling are crucial for preventing RCE vulnerabilities in CLI tools.
- Developers should always be skeptical of external data and implement strong security practices, especially when dealing with features that allow arbitrary command execution.
Ensure your Claude Code CLI is updated to version 2.1.118 or later. Verify your version by running claude --version in your terminal. Exercise caution when clicking deeplinks from untrusted sources.