From c0e1f8f1a5fbdb45079770dac9a9232db238dddb Mon Sep 17 00:00:00 2001 From: B <6723574+louisgv@users.noreply.github.com> Date: Thu, 12 Mar 2026 22:59:53 +0000 Subject: [PATCH] security: use shellQuote() in agent-setup.ts for consistent null-byte defense Agent: code-health Co-Authored-By: Claude Sonnet 4.5 --- packages/cli/package.json | 2 +- packages/cli/src/shared/agent-setup.ts | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index d035b5f57..8cb019127 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@openrouter/spawn", - "version": "0.17.0", + "version": "0.17.1", "type": "module", "bin": { "spawn": "cli.js" diff --git a/packages/cli/src/shared/agent-setup.ts b/packages/cli/src/shared/agent-setup.ts index 7a45fc9f0..58a3d33d9 100644 --- a/packages/cli/src/shared/agent-setup.ts +++ b/packages/cli/src/shared/agent-setup.ts @@ -9,7 +9,7 @@ import { join } from "node:path"; import { getTmpDir } from "./paths"; import { asyncTryCatch, asyncTryCatchIf, isOperationalError, tryCatchIf } from "./result.js"; import { getErrorMessage } from "./type-guards"; -import { Err, jsonEscape, logError, logInfo, logStep, logWarn, Ok, withRetry } from "./ui"; +import { Err, jsonEscape, logError, logInfo, logStep, logWarn, Ok, shellQuote, withRetry } from "./ui"; /** * Wrap an SSH-based async operation into a Result for use with withRetry. @@ -240,8 +240,7 @@ export async function offerGithubAuth(runner: CloudRunner): Promise { let ghCmd = "curl --proto '=https' -fsSL https://openrouter.ai/labs/spawn/shared/github-auth.sh | bash"; if (githubToken) { - const escaped = githubToken.replace(/'/g, "'\\''"); - ghCmd = `export GITHUB_TOKEN='${escaped}' && ${ghCmd}`; + ghCmd = `export GITHUB_TOKEN=${shellQuote(githubToken)} && ${ghCmd}`; } logStep("Installing and authenticating GitHub CLI on the remote server..."); @@ -255,12 +254,10 @@ export async function offerGithubAuth(runner: CloudRunner): Promise { logStep("Configuring git identity on the remote server..."); const cmds: string[] = []; if (hostGitName) { - const escaped = hostGitName.replace(/'/g, "'\\''"); - cmds.push(`git config --global user.name '${escaped}'`); + cmds.push(`git config --global user.name ${shellQuote(hostGitName)}`); } if (hostGitEmail) { - const escaped = hostGitEmail.replace(/'/g, "'\\''"); - cmds.push(`git config --global user.email '${escaped}'`); + cmds.push(`git config --global user.email ${shellQuote(hostGitEmail)}`); } const gitSetup = await asyncTryCatchIf(isOperationalError, () => runner.runServer(cmds.join(" && "))); if (gitSetup.ok) {