From ef7b67752ebaea225c03fc8792723fca8f30b6c7 Mon Sep 17 00:00:00 2001 From: A <258483684+la14-1@users.noreply.github.com> Date: Sat, 21 Feb 2026 19:11:55 -0800 Subject: [PATCH] fix: prevent GitHub token exposure via process listing (#1661) Write GITHUB_TOKEN to a temp file with 0600 permissions instead of inlining in the command string, preventing exposure via ps aux and /proc/*/cmdline. Fixes #1659 Agent: security-auditor Co-authored-by: B <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.5 --- cli/src/fly/agents.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cli/src/fly/agents.ts b/cli/src/fly/agents.ts index 480521f1..8fd1c0b3 100644 --- a/cli/src/fly/agents.ts +++ b/cli/src/fly/agents.ts @@ -213,9 +213,23 @@ export async function offerGithubAuth(): Promise { if (!githubAuthRequested) return; let ghCmd = "curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/shared/github-auth.sh | bash"; + let localTmpFile = ""; if (githubToken) { const escaped = githubToken.replace(/'/g, "'\\''"); - ghCmd = `export GITHUB_TOKEN='${escaped}'; ${ghCmd}`; + // Write token to a local temp file with restricted permissions, then upload + // to the remote machine. This prevents the token from appearing in process + // argument lists (ps aux, /proc/*/cmdline) on either machine. + localTmpFile = join(tmpdir(), `gh_token_${Date.now()}_${Math.random().toString(36).slice(2)}`); + writeFileSync(localTmpFile, `export GITHUB_TOKEN='${escaped}'`, { mode: 0o600 }); + const remoteTmpFile = `/tmp/gh_token_${Date.now()}`; + try { + await uploadFile(localTmpFile, remoteTmpFile); + ghCmd = `. ${remoteTmpFile} && rm -f ${remoteTmpFile} && ${ghCmd}`; + } catch { + // Fallback: if upload fails, clean up and skip token injection + try { unlinkSync(localTmpFile); } catch { /* ignore */ } + localTmpFile = ""; + } } logStep("Installing and authenticating GitHub CLI..."); @@ -223,6 +237,10 @@ export async function offerGithubAuth(): Promise { await runServer(ghCmd); } catch { logWarn("GitHub CLI setup failed (non-fatal, continuing)"); + } finally { + if (localTmpFile) { + try { unlinkSync(localTmpFile); } catch { /* ignore */ } + } } }