Summary
On Windows, openBrowser (src/reasoning/login.ts) opens the login URL by shelling out to cmd:
// src/reasoning/login.ts:78-84
const [cmd, args] =
process.platform === 'darwin' ? ['open', [url]]
: process.platform === 'win32' ? ['cmd', ['/c', 'start', '', url]]
: ['xdg-open', [url]];
const child = spawn(cmd, args, { stdio: 'ignore', detached: true, windowsHide: true });
spawn runs without shell: true, so Node does not shell-parse the argv — good. But cmd.exe then re-parses the arguments to its start built-in, so shell metacharacters (&, |, ^, ") inside url are interpreted by cmd, not treated as a literal URL.
How url gets there
openBrowser is called from the codegraph login device-flow. The URL is external input:
startDeviceLogin() (login.ts:36) fetches verification_uri / verification_uri_complete from the dashboard (app.getcodegraph.com), and
- the base is overridable via the
CODEGRAPH_LOGIN_URL env var (loginBaseUrl(), login.ts:17).
So the string reaching cmd /c start originates from a remote response or an environment variable — not a hardcoded constant.
Impact
Defense-in-depth only. To exploit it an attacker needs to control that URL — i.e. MITM/compromise the first-party HTTPS endpoint, or poison CODEGRAPH_LOGIN_URL in the victim's environment. Given either, a crafted URL (e.g. containing &calc) could inject an additional command on Windows when the user runs codegraph login. macOS (open) and Linux (xdg-open) pass the URL as a single argv element and are not affected. Low severity, but it's untrusted input reaching a cmd invocation.
Suggested fix
Either validate before spawning — reject a url that doesn't match ^https?:// — or open it without going through cmd start, e.g. spawn('rundll32', ['url.dll,FileProtocolHandler', url]) (or ShellExecute), which takes the URL as a single opaque argument.
Environment
- Found on
main (tip 3424ff3); Windows only. Not yet in a tagged release.
Reported from a red-team pass. Reachability of the call chain confirmed against the current graph.
Summary
On Windows,
openBrowser(src/reasoning/login.ts) opens the login URL by shelling out tocmd:spawnruns withoutshell: true, so Node does not shell-parse the argv — good. Butcmd.exethen re-parses the arguments to itsstartbuilt-in, so shell metacharacters (&,|,^,") insideurlare interpreted by cmd, not treated as a literal URL.How
urlgets thereopenBrowseris called from thecodegraph logindevice-flow. The URL is external input:startDeviceLogin()(login.ts:36) fetchesverification_uri/verification_uri_completefrom the dashboard (app.getcodegraph.com), andCODEGRAPH_LOGIN_URLenv var (loginBaseUrl(),login.ts:17).So the string reaching
cmd /c startoriginates from a remote response or an environment variable — not a hardcoded constant.Impact
Defense-in-depth only. To exploit it an attacker needs to control that URL — i.e. MITM/compromise the first-party HTTPS endpoint, or poison
CODEGRAPH_LOGIN_URLin the victim's environment. Given either, a crafted URL (e.g. containing&calc) could inject an additional command on Windows when the user runscodegraph login. macOS (open) and Linux (xdg-open) pass the URL as a single argv element and are not affected. Low severity, but it's untrusted input reaching acmdinvocation.Suggested fix
Either validate before spawning — reject a
urlthat doesn't match^https?://— or open it without going throughcmd start, e.g.spawn('rundll32', ['url.dll,FileProtocolHandler', url])(orShellExecute), which takes the URL as a single opaque argument.Environment
main(tip3424ff3); Windows only. Not yet in a tagged release.Reported from a red-team pass. Reachability of the call chain confirmed against the current graph.