From d9ef76f1acf12c702bd1cf5c9e2c307781088c48 Mon Sep 17 00:00:00 2001 From: Peter Evans <18365890+peter-evans@users.noreply.github.com> Date: Fri, 23 Jan 2026 10:06:08 +0000 Subject: [PATCH] fix(security): prevent path traversal in credentials file deletion Use path.resolve() to normalize paths before comparison in removeIncludeIfCredentials(). The previous startsWith() check was vulnerable to path traversal attacks where a path like "/tmp/runner/../../../etc/passwd" would pass the check but resolve outside RUNNER_TEMP. Also append path.sep to prevent false positives (e.g., /tmp/runner2 matching /tmp/runner). --- dist/index.js | 5 ++++- src/git-config-helper.ts | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dist/index.js b/dist/index.js index ecdd195..c0140ab 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1392,7 +1392,10 @@ class GitConfigHelper { } // Delete only our credentials config file const runnerTemp = process.env['RUNNER_TEMP']; - if (runnerTemp && this.credentialsConfigPath.startsWith(runnerTemp)) { + const resolvedCredentialsPath = path.resolve(this.credentialsConfigPath); + const resolvedRunnerTemp = runnerTemp ? path.resolve(runnerTemp) : ''; + if (resolvedRunnerTemp && + resolvedCredentialsPath.startsWith(resolvedRunnerTemp + path.sep)) { try { yield fs.promises.unlink(this.credentialsConfigPath); core.info(`Removed credentials config file: ${this.credentialsConfigPath}`); diff --git a/src/git-config-helper.ts b/src/git-config-helper.ts index 4af25a0..bee89c1 100644 --- a/src/git-config-helper.ts +++ b/src/git-config-helper.ts @@ -303,7 +303,12 @@ export class GitConfigHelper { // Delete only our credentials config file const runnerTemp = process.env['RUNNER_TEMP'] - if (runnerTemp && this.credentialsConfigPath.startsWith(runnerTemp)) { + const resolvedCredentialsPath = path.resolve(this.credentialsConfigPath) + const resolvedRunnerTemp = runnerTemp ? path.resolve(runnerTemp) : '' + if ( + resolvedRunnerTemp && + resolvedCredentialsPath.startsWith(resolvedRunnerTemp + path.sep) + ) { try { await fs.promises.unlink(this.credentialsConfigPath) core.info(