Skip to content

security: [HIGH] GitHub token exposure via temporary files with race condition #2462

@louisgv

Description

@louisgv

Summary

GitHub tokens are written to temporary files during the GitHub CLI authentication flow. The files use predictable names and exist briefly on disk, creating a race condition window where other processes could access the token.

Location

packages/cli/src/shared/agent-setup.ts:214-246

Current Implementation

const 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 runner.uploadFile(localTmpFile, remoteTmpFile);
  ghCmd = `. ${remoteTmpFile} && rm -f ${remoteTmpFile} && ${ghCmd}`;
} catch {
  try {
    unlinkSync(localTmpFile);
  } catch {
    /* ignore */
  }
  localTmpFile = "";
}

Vulnerability

  1. Local race condition: Token file exists on disk between writeFileSync() and unlinkSync()
  2. Predictable filenames: Using Date.now() makes filenames guessable
  3. Remote exposure: Remote temp file persists until the command deletes it

While the file is created with mode 0o600 (owner-only), there's still a window where:

  • Other processes with the same UID can read it
  • System monitoring tools could log/backup the file
  • Crashes/interruptions could leave the file undeleted

Risk Assessment

  • Severity: HIGH
  • Likelihood: LOW (requires local or remote file access during narrow window)
  • Impact: GitHub token compromise → full repository access

Recommendation

Use environment variable passing instead of temp files:

// For remote execution, pass token via SSH -o SendEnv
const ghCmd = `curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/sh/shared/github-auth.sh | bash`;
await runner.runServer(ghCmd, {
  env: { GITHUB_TOKEN: githubToken }
});

Alternatively, use Bun's process substitution via /dev/fd if available.

-- security/code-scanner

Metadata

Metadata

Assignees

No one assigned

    Labels

    safe-to-workSecurity triage: safe for automated processing

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions