Summary
installClaudeCode() in src/entrypoints/run.ts appends PATH_TO_CLAUDE_CODE_EXECUTABLE's parent directory into GITHUB_PATH without sanitizing the value first:
const customExecutable = process.env.PATH_TO_CLAUDE_CODE_EXECUTABLE;
if (customExecutable) {
const claudeDir = dirname(customExecutable);
if (githubPath) {
await appendFile(githubPath, `${claudeDir}\n`); // line 55
}
GITHUB_PATH is a runner-managed file where each line is a directory to add to PATH for subsequent steps. If PATH_TO_CLAUDE_CODE_EXECUTABLE contains embedded newlines (e.g. /usr/local/bin/claude\n/attacker/path), dirname() passes through the embedded newline, and appendFile writes two lines — injecting an attacker-controlled directory into the runner's PATH.
Impact
Any workflow that sets PATH_TO_CLAUDE_CODE_EXECUTABLE from an untrusted source (e.g. a workflow input, an environment variable populated from PR metadata) could have additional directories injected into the runner PATH for all subsequent steps in that job. This could be used to shadow system binaries.
In practice, PATH_TO_CLAUDE_CODE_EXECUTABLE is typically set by the workflow author, so the immediate risk is low. However, defense-in-depth sanitization is appropriate for anything written to runner environment files.
Proposed fix
Strip control characters (including \n, \r, null bytes) from claudeDir before writing to GITHUB_PATH:
const safePath = claudeDir.replace(/[\x00-\x1f\x7f]/g, "");
await appendFile(githubPath, `${safePath}\n`);
Or throw if the sanitized value differs from the original (fail-closed rather than silently stripping).
References
Summary
installClaudeCode()insrc/entrypoints/run.tsappendsPATH_TO_CLAUDE_CODE_EXECUTABLE's parent directory intoGITHUB_PATHwithout sanitizing the value first:GITHUB_PATHis a runner-managed file where each line is a directory to add toPATHfor subsequent steps. IfPATH_TO_CLAUDE_CODE_EXECUTABLEcontains embedded newlines (e.g./usr/local/bin/claude\n/attacker/path),dirname()passes through the embedded newline, andappendFilewrites two lines — injecting an attacker-controlled directory into the runner's PATH.Impact
Any workflow that sets
PATH_TO_CLAUDE_CODE_EXECUTABLEfrom an untrusted source (e.g. a workflow input, an environment variable populated from PR metadata) could have additional directories injected into the runner PATH for all subsequent steps in that job. This could be used to shadow system binaries.In practice,
PATH_TO_CLAUDE_CODE_EXECUTABLEis typically set by the workflow author, so the immediate risk is low. However, defense-in-depth sanitization is appropriate for anything written to runner environment files.Proposed fix
Strip control characters (including
\n,\r, null bytes) fromclaudeDirbefore writing toGITHUB_PATH:Or throw if the sanitized value differs from the original (fail-closed rather than silently stripping).
References
run.tslines 48-59