Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions packages/spotlight/src/server/cli/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ export async function handler({
if (open) {
openInBrowser(actualServerPort);
}
let shell = false;
let stdin: string | undefined = undefined;
const env = {
...process.env,
Expand Down Expand Up @@ -238,8 +237,11 @@ export async function handler({
} else {
logger.info(`Using package.json script: ${packageJson.scriptName}`);
metrics.count("cli.run.autodetect", 1, { attributes: { type: "package-json" } });
cmdArgs = [packageJson.scriptCommand];
shell = true;
// Use explicit shell invocation instead of shell=true to avoid command injection risks
// This provides the same functionality while being more explicit about shell execution
const shellExecutable = process.platform === "win32" ? "cmd.exe" : "sh";
const shellFlag = process.platform === "win32" ? "/c" : "-c";
cmdArgs = [shellExecutable, shellFlag, packageJson.scriptCommand];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Windows shell invocation missing /d and /s flags

Medium Severity

On Windows, Node.js shell: true internally invokes cmd.exe /d /s /c "command", but the replacement only uses /c. The missing /d flag means registry AutoRun commands could execute before the user's script (ironically a security regression for a security fix). The missing /s flag changes how cmd.exe handles quote stripping after /c, which can break scripts containing quoted arguments (e.g., node -e "console.log('hi')"). The command also isn't wrapped in double quotes as Node.js does internally.

Additional Locations (1)

Fix in Cursor Fix in Web

env.PATH = path.resolve("./node_modules/.bin") + path.delimiter + env.PATH;
}
} else if (dockerCompose) {
Expand All @@ -251,8 +253,11 @@ export async function handler({
} else if (packageJson) {
logger.info(`Using package.json script: ${packageJson.scriptName}`);
metrics.count("cli.run.autodetect", 1, { attributes: { type: "package-json" } });
cmdArgs = [packageJson.scriptCommand];
shell = true;
// Use explicit shell invocation instead of shell=true to avoid command injection risks
// This provides the same functionality while being more explicit about shell execution
const shellExecutable = process.platform === "win32" ? "cmd.exe" : "sh";
const shellFlag = process.platform === "win32" ? "/c" : "-c";
cmdArgs = [shellExecutable, shellFlag, packageJson.scriptCommand];
env.PATH = path.resolve("./node_modules/.bin") + path.delimiter + env.PATH;
}
} else {
Expand Down Expand Up @@ -283,7 +288,6 @@ export async function handler({
const runCmd = spawn(cmdArgs[0], cmdArgs.slice(1), {
cwd: process.cwd(),
env,
shell,
windowsVerbatimArguments: true,
windowsHide: true,
stdio: [stdinMode, "pipe", "pipe"],
Expand Down
Loading