From 5c4ee735bd5f23953b027aa7f0682f6cf5cbdc82 Mon Sep 17 00:00:00 2001 From: B <6723574+louisgv@users.noreply.github.com> Date: Sat, 25 Apr 2026 08:22:00 +0000 Subject: [PATCH] fix(security): base64-encode values in /etc/spawn/secrets to prevent shell injection Replace shell-sourceable export NAME="VALUE" format with NAME=BASE64VALUE, decoded at source-time via a loader in ~/.bashrc. This eliminates deferred code execution when API keys contain quotes, newlines, or shell metacharacters. Also removes old `source /etc/spawn/secrets` lines from ~/.bashrc in favor of the safe base64-decoding loader. Fixes #3361 Agent: security-auditor Co-Authored-By: Claude Sonnet 4.6 --- packages/cli/src/shared/spawn-md.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/shared/spawn-md.ts b/packages/cli/src/shared/spawn-md.ts index 6dfac623..09d05210 100644 --- a/packages/cli/src/shared/spawn-md.ts +++ b/packages/cli/src/shared/spawn-md.ts @@ -390,11 +390,15 @@ async function applySetupStep(runner: CloudRunner, step: SetupStep): Promise> /etc/spawn/secrets && chmod 600 /etc/spawn/secrets`, + `mkdir -p /etc/spawn && printf '%s=%s\\n' '${escapedName}' '${b64Val}' >> /etc/spawn/secrets && chmod 600 /etc/spawn/secrets`, ); + // Install a loader that decodes base64 at source-time instead of shell-sourcing + const loaderSnippet = + 'while IFS="=" read -r k v; do [ -n "$k" ] && export "$k=$(printf "%s" "$v" | base64 -d)"; done < /etc/spawn/secrets'; await runner.runServer( - `grep -q '/etc/spawn/secrets' ~/.bashrc 2>/dev/null || echo 'source /etc/spawn/secrets 2>/dev/null' >> ~/.bashrc`, + `grep -q 'while IFS.*secrets' ~/.bashrc 2>/dev/null || { sed -i '/source.*\\/etc\\/spawn\\/secrets/d' ~/.bashrc 2>/dev/null; echo '${loaderSnippet}' >> ~/.bashrc; }`, ); logInfo(` ${step.name} saved`); } else {