diff --git a/packages/cli/package.json b/packages/cli/package.json index 0aee82efd..7d7c32810 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@openrouter/spawn", - "version": "1.0.5", + "version": "1.0.6", "type": "module", "bin": { "spawn": "cli.js" diff --git a/packages/cli/src/__tests__/update-check.test.ts b/packages/cli/src/__tests__/update-check.test.ts index 6177b5e9f..74c5d4319 100644 --- a/packages/cli/src/__tests__/update-check.test.ts +++ b/packages/cli/src/__tests__/update-check.test.ts @@ -313,9 +313,9 @@ describe("update-check", () => { expect(execFileSyncCalls[0].file).toBe("curl"); expect(execFileSyncCalls[0].args).toContain("-fsSL"); expect(execFileSyncCalls[0].args.some((a: string) => a.includes("install.sh"))).toBe(true); - // 2. bash to execute fetched script + // 2. bash to execute fetched script via temp file (not -c) expect(execFileSyncCalls[1].file).toBe("bash"); - expect(execFileSyncCalls[1].args[0]).toBe("-c"); + expect(execFileSyncCalls[1].args[0]).toMatch(/spawn-install-.*\.sh$/); // 3. which spawn for binary lookup expect(execFileSyncCalls[2].file).toBe("which"); expect(execFileSyncCalls[2].args).toEqual([ diff --git a/packages/cli/src/update-check.ts b/packages/cli/src/update-check.ts index 6eb969327..10310f5e5 100644 --- a/packages/cli/src/update-check.ts +++ b/packages/cli/src/update-check.ts @@ -320,17 +320,28 @@ function performAutoUpdate(latestVersion: string, jsonOutput = false): void { throw psResult.error; } } else { - // macOS/Linux: execute via bash -c - executor.execFileSync( - "bash", - [ - "-c", - scriptContent, - ], - { - stdio: installStdio, - }, + // macOS/Linux: write to temp file and execute via bash to avoid + // command injection and ARG_MAX limits (consistent with Windows path) + const tmpFile = path.join(tmpdir(), `spawn-install-${Date.now()}.sh`); + fs.writeFileSync(tmpFile, scriptContent, { + mode: 0o700, + }); + const bashResult = tryCatch(() => + executor.execFileSync( + "bash", + [ + tmpFile, + ], + { + stdio: installStdio, + }, + ), ); + // Best-effort cleanup of temp file + tryCatchIf(isFileError, () => fs.unlinkSync(tmpFile)); + if (!bashResult.ok) { + throw bashResult.error; + } } });