$BROWSER: OAuth URL wrapped in literal quotes; on Windows a .cmd target truncates it at `=` and executes `&` query fragments via cmd.exe
What happened
When Claude Code opens an OAuth/sign-in URL, it launches the $BROWSER executable with the URL pre-wrapped in literal double-quotes ("<url>") via a no-shell spawn (the URL is passed as a raw argument, not run through a shell). This causes two distinct failures depending on platform:
Windows (when $BROWSER points to a .cmd/.bat target):
A .cmd/.bat cannot be spawned directly the way a native .exe can, so Windows re-invokes it through cmd.exe. cmd.exe re-parses the MSVCRT-escaped command line with broken quote state, and two things go wrong with a typical OAuth URL such as https://claude.ai/oauth/authorize?code=abc&state=xyz:
- The URL is truncated at the first
=. The child receives a leading-literal-quote fragment cut off at the first=. Observed live, the browser navigated to"https//claude.ai/oauth/authorize?code(note the missing:is a downstream artifact; the key point is truncation at=). &-split query fragments are executed as commands. Because the URL is no longer inside intact quoting after the re-parse,cmd.exetreats&as a command separator and executes the query-string fragments (e.g.state=xyz) as separate shell commands. This is the same vulnerability class as CVE-2024-27980 (Node.js.bat/.cmdargument handling on Windows).
Linux:
The URL arrives as a single intact argv element but still wrapped in a literal quote pair ("<url>"), so the receiving browser/target sees the surrounding quotes as part of the URL unless it strips them.
Expected
$BROWSER should be invoked with the URL as a clean, single argument — no surrounding literal quotes, and never in a way that lets a .cmd/.bat intermediary re-split the URL's &/= characters. On Windows specifically, either the target should be invoked without a cmd.exe re-parse, or the URL should be quoted/escaped so it survives the cmd.exe hop intact.
Impact
- OAuth sign-in through a custom
$BROWSER(.cmd/.batwrapper) fails outright on Windows — the browser gets a truncated URL and the auth code never reaches the correct endpoint. - The
&-fragment execution is a command-injection surface: any attacker-influenced or malformed query fragment following an&is handed tocmd.exeas a command.
Environment
- Claude Code v2.1.x (observed on v2.1.207), Windows 10/11.
$BROWSERset to a.cmdwrapper (required because a.ps1cannot be used as aCreateProcessexec target directly).
Workaround we're using
In our $BROWSER shim we (a) Trim('"') the incoming argument on both platforms, and (b) on Windows recover the un-mangled URL from the parent cmd.exe's raw command line (Win32_Process.CommandLine), taking the first https://… run and stripping cmd's ^ escapes. This mitigates the URL truncation, but the &-fragment command execution happens in the cmd.exe hop before our shim runs and is not fixable from outside Claude Code.
Suggested fix direction
Pass the URL to $BROWSER without wrapping it in literal quotes, and on Windows avoid (or properly escape for) the cmd.exe re-parse when the target is a .cmd/.bat — mirroring the guidance from the CVE-2024-27980 remediation.