From c69c12c8dbeffda7b460651bf15e75dbb644c51e Mon Sep 17 00:00:00 2001 From: A <258483684+la14-1@users.noreply.github.com> Date: Fri, 20 Feb 2026 09:52:02 -0800 Subject: [PATCH] fix: validate RAW_BASE URL in update-check to prevent future injection (#1533) Agent: security-auditor Co-authored-by: B <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.5 --- cli/src/manifest.ts | 2 +- cli/src/update-check.ts | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cli/src/manifest.ts b/cli/src/manifest.ts index 05b70852..46bb7736 100644 --- a/cli/src/manifest.ts +++ b/cli/src/manifest.ts @@ -56,7 +56,7 @@ export interface Manifest { // ── Constants ────────────────────────────────────────────────────────────────── const REPO = "OpenRouterTeam/spawn"; -const RAW_BASE = `https://raw.githubusercontent.com/${REPO}/main`; +const RAW_BASE = `https://raw.githubusercontent.com/${REPO}/main` as const; // Dynamic getters so tests can override XDG_CACHE_HOME at runtime function getCacheDir(): string { return join(process.env.XDG_CACHE_HOME || join(homedir(), ".cache"), "spawn"); diff --git a/cli/src/update-check.ts b/cli/src/update-check.ts index 504697c0..ac001af6 100644 --- a/cli/src/update-check.ts +++ b/cli/src/update-check.ts @@ -16,6 +16,12 @@ export const executor = { const FETCH_TIMEOUT = 5000; // 5 seconds +// Validate RAW_BASE matches expected GitHub raw content URL pattern (defense-in-depth, CWE-78) +const GITHUB_RAW_URL_PATTERN = /^https:\/\/raw\.githubusercontent\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/; +if (!GITHUB_RAW_URL_PATTERN.test(RAW_BASE)) { + throw new Error(`RAW_BASE URL does not match expected GitHub raw URL pattern: ${RAW_BASE}`); +} + // Use ASCII-safe symbols when unicode is disabled (SSH, dumb terminals) const isAscii = process.env.TERM === "linux"; const CHECK_MARK = isAscii ? "*" : "\u2713";