Skip to content

Commit 75ca0f6

Browse files
committed
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
1 parent 813ff4c commit 75ca0f6

1 file changed

Lines changed: 13 additions & 5 deletions

File tree

src/auth/oauth.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,21 @@ export async function startBrowserFlow(
4444

4545
const authUrl = `${config.authorizationUrl}?${params}`;
4646

47-
// Open browser
48-
const { exec } = await import('child_process');
47+
// Open browser using execFile/spawn instead of exec to prevent shell injection.
48+
// exec() passes the string to a shell, so a crafted authUrl containing shell
49+
// metacharacters (e.g. from a malicious authorization server redirect) could
50+
// execute arbitrary commands. execFile/spawn bypass the shell entirely. (#79)
51+
const { execFile, spawn } = await import('child_process');
4952
const platform = process.platform;
50-
const openCmd = platform === 'darwin' ? 'open' :
51-
platform === 'win32' ? 'start' : 'xdg-open';
5253

53-
exec(`${openCmd} "${authUrl}"`);
54+
if (platform === 'darwin') {
55+
execFile('open', [authUrl]);
56+
} else if (platform === 'win32') {
57+
// On Windows, 'start' is a shell built-in — use cmd.exe /c start explicitly.
58+
spawn('cmd.exe', ['/c', 'start', '', authUrl], { shell: false, detached: true });
59+
} else {
60+
execFile('xdg-open', [authUrl]);
61+
}
5462
process.stderr.write('Opening browser to authenticate with MiniMax...\n');
5563

5664
// Start local server to receive callback

0 commit comments

Comments
 (0)