Skip to content

security(low): openBrowser routes a server-supplied URL through Windows cmd /c start unescaped #1114

Description

@inth3shadows

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions