From 75ca0f69bae2bef5d8d751471c2d48045ff3a436 Mon Sep 17 00:00:00 2001 From: draix Date: Tue, 14 Apr 2026 02:24:51 -0300 Subject: [PATCH] fix(auth): replace exec() with execFile/spawn to prevent shell injection (#79) src/auth/oauth.ts passed the OAuth authorization URL directly to exec(): exec(`${openCmd} "${authUrl}"`) exec() passes the string to a shell (/bin/sh on Unix, cmd.exe on Windows). A crafted authorization URL containing shell metacharacters (e.g. from a malicious or tampered authorization server redirect) could execute arbitrary commands on the user's machine. Fix: replace exec() with execFile() on macOS/Linux (which bypasses the shell entirely) and spawn() on Windows (since 'start' is a shell built-in that requires cmd.exe, spawned with shell:false and an explicit empty title arg to prevent argument injection). Closes part of #79 --- src/auth/oauth.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/auth/oauth.ts b/src/auth/oauth.ts index 41ad861..530f03e 100644 --- a/src/auth/oauth.ts +++ b/src/auth/oauth.ts @@ -44,13 +44,21 @@ export async function startBrowserFlow( const authUrl = `${config.authorizationUrl}?${params}`; - // Open browser - const { exec } = await import('child_process'); + // Open browser using execFile/spawn instead of exec to prevent shell injection. + // exec() passes the string to a shell, so a crafted authUrl containing shell + // metacharacters (e.g. from a malicious authorization server redirect) could + // execute arbitrary commands. execFile/spawn bypass the shell entirely. (#79) + const { execFile, spawn } = await import('child_process'); const platform = process.platform; - const openCmd = platform === 'darwin' ? 'open' : - platform === 'win32' ? 'start' : 'xdg-open'; - exec(`${openCmd} "${authUrl}"`); + if (platform === 'darwin') { + execFile('open', [authUrl]); + } else if (platform === 'win32') { + // On Windows, 'start' is a shell built-in — use cmd.exe /c start explicitly. + spawn('cmd.exe', ['/c', 'start', '', authUrl], { shell: false, detached: true }); + } else { + execFile('xdg-open', [authUrl]); + } process.stderr.write('Opening browser to authenticate with MiniMax...\n'); // Start local server to receive callback