CVE-2025-32955
Description
Harden-Runner is a CI/CD security agent that works like an EDR for GitHub Actions runners. Versions from 0.12.0 to before 2.12.0 are vulnerable to disable-sudo bypass. Harden-Runner includes a policy option disable-sudo to prevent the GitHub Actions runner user from using sudo. This is implemented by removing the runner user from the sudoers file. However, this control can be bypassed as the runner user, being part of the docker group, can interact with the Docker daemon to launch privileged containers or access the host filesystem. This allows the attacker to regain root access or restore the sudoers file, effectively bypassing the restriction. This issue has been patched in version 2.12.0.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
step-security/harden-runnerGitHub Actions | >= 0.12.0, < 2.12.0 | 2.12.0 |
Patches
10634a2670c59Merge pull request #541 from step-security/rc-20
13 files changed · +49 −17
action.yml+5 −1 modified@@ -17,7 +17,11 @@ inputs: required: false default: "false" disable-sudo: - description: "Disable sudo access for the runner account" + description: "Disable sudo access for the runner account. Note: This parameter will be deprecated in the future. Please use disable-sudo-and-containers instead." + required: false + default: "false" + disable-sudo-and-containers: + description: "Disable sudo and container access for the runner account" required: false default: "false" disable-file-monitoring:
dist/post/index.js+2 −1 modified@@ -27947,7 +27947,8 @@ var cleanup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ console.log(content); } var disable_sudo = process.env.STATE_disableSudo; - if (disable_sudo !== "true") { + var disable_sudo_and_containers = process.env.STATE_disableSudoAndContainers; + if (disable_sudo !== "true" && disable_sudo_and_containers !== "true") { try { var journalLog = external_child_process_.execSync("sudo journalctl -u agent.service --lines=1000", { encoding: "utf8",
dist/post/index.js.map+1 −1 modifieddist/pre/index.js+12 −5 modified@@ -87890,6 +87890,9 @@ function mergeConfigs(localConfig, remoteConfig) { if (remoteConfig.disable_sudo !== undefined) { localConfig.disable_sudo = remoteConfig.disable_sudo; } + if (remoteConfig.disable_sudo_and_containers !== undefined) { + localConfig.disable_sudo_and_containers = remoteConfig.disable_sudo_and_containers; + } if (remoteConfig.disable_file_monitoring !== undefined) { localConfig.disable_file_monitoring = remoteConfig.disable_file_monitoring; } @@ -88004,11 +88007,11 @@ var external_crypto_ = __nccwpck_require__(6417); const CHECKSUMS = { tls: { - amd64: "38e7ed97ced6fe0c1cf0fb5ee3b3d521dfe28d5ddf1cdca72d130c8d1b4a314e", - arm64: "f67c80cc578c996d4f882c14fcdb63df57927d907cd22f1ec65f9fa940c08cf3", + amd64: "e7c0c5f96efbf96806d27dcbf65f71f72ecd34cdd596c556bb2ded0f2037c260", + arm64: "813a4cd40f6740bd9623a40884a78f14960c6bd3794391693a165f2ca71c90e3", }, non_tls: { - amd64: "a9f1842e3d7f3d38c143dbe8ffe1948e6c8173cd04da072d9f9d128bb400844a", // v0.13.7 + amd64: "f0a8bb49ce5480744f8c836af2abd5f311e918efef5b36b4cce7521d7b9dffe6", // v0.14.0 }, }; function verifyChecksum(downloadPath, isTLS, variant) { @@ -88058,14 +88061,14 @@ function installAgent(isTLS, configStr) { encoding: "utf8", }); if (isTLS) { - downloadPath = yield tool_cache.downloadTool(`https://packages.stepsecurity.io/github-hosted/harden-runner_1.4.2_linux_${variant}.tar.gz`); + downloadPath = yield tool_cache.downloadTool(`https://packages.stepsecurity.io/github-hosted/harden-runner_1.6.3_linux_${variant}.tar.gz`); } else { if (variant === "arm64") { console.log(ARM64_RUNNER_MESSAGE); return false; } - downloadPath = yield tool_cache.downloadTool("https://github.com/step-security/agent/releases/download/v0.13.7/agent_0.13.7_linux_amd64.tar.gz", undefined, auth); + downloadPath = yield tool_cache.downloadTool("https://github.com/step-security/agent/releases/download/v0.14.0/agent_0.14.0_linux_amd64.tar.gz", undefined, auth); } verifyChecksum(downloadPath, isTLS, variant); const extractPath = yield tool_cache.extractTar(downloadPath); @@ -88142,6 +88145,7 @@ var setup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar egress_policy: lib_core.getInput("egress-policy"), disable_telemetry: lib_core.getBooleanInput("disable-telemetry"), disable_sudo: lib_core.getBooleanInput("disable-sudo"), + disable_sudo_and_containers: lib_core.getBooleanInput("disable-sudo-and-containers"), disable_file_monitoring: lib_core.getBooleanInput("disable-file-monitoring"), private: ((_b = (_a = github.context === null || github.context === void 0 ? void 0 : github.context.payload) === null || _a === void 0 ? void 0 : _a.repository) === null || _b === void 0 ? void 0 : _b.private) || false, is_github_hosted: isGithubHosted(), @@ -88164,6 +88168,9 @@ var setup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar external_fs_.appendFileSync(process.env.GITHUB_STATE, `disableSudo=${confg.disable_sudo}${external_os_.EOL}`, { encoding: "utf8", }); + external_fs_.appendFileSync(process.env.GITHUB_STATE, `disableSudoAndContainers=${confg.disable_sudo_and_containers}${external_os_.EOL}`, { + encoding: "utf8", + }); lib_core.info(`[!] Current Configuration: \n${JSON.stringify(confg)}\n`); if (confg.egress_policy !== "audit" && confg.egress_policy !== "block") { lib_core.setFailed("egress-policy must be either audit or block");
dist/pre/index.js.map+1 −1 modifiedREADME.md+4 −2 modified@@ -66,7 +66,8 @@ To integrate Harden-Runner, follow these steps: - Add the following code as the first step in each job: ```yaml steps: - - uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 with: egress-policy: audit @@ -134,7 +135,7 @@ Explore the full feature set in the [Features Documentation](https://docs.stepse ## Trusted By and Case Studies -Harden-Runner is trusted by over 5000 leading open-source projects and enterprises, including Microsoft, Google, Kubernetes, and more. +Harden-Runner is trusted by over 6000 leading open-source projects and enterprises, including Microsoft, Google, Kubernetes, and more. ### Trusted by @@ -147,6 +148,7 @@ Harden-Runner is trusted by over 5000 leading open-source projects and enterpris - [How Coveo Strengthened GitHub Actions Security with StepSecurity](https://www.stepsecurity.io/case-studies/coveo) - [Hashgraph Achieves Comprehensive CI/CD Security Without Compromising Development Speed](https://www.stepsecurity.io/case-studies/hashgraph) +- [Chainguard Secures GitHub Actions with StepSecurity](https://www.stepsecurity.io/case-studies/chainguard) - [Kapiche secures their GitHub Actions software supply chain with Harden-Runner](https://www.stepsecurity.io/case-studies/kapiche) - [Arcjet Enhances CI/CD Security with Harden-Runner](https://www.stepsecurity.io/case-studies/arcjet)
src/checksum.ts+3 −3 modified@@ -4,11 +4,11 @@ import * as fs from "fs"; const CHECKSUMS = { tls: { - amd64: "38e7ed97ced6fe0c1cf0fb5ee3b3d521dfe28d5ddf1cdca72d130c8d1b4a314e", // v1.4.2 - arm64: "f67c80cc578c996d4f882c14fcdb63df57927d907cd22f1ec65f9fa940c08cf3", + amd64: "e7c0c5f96efbf96806d27dcbf65f71f72ecd34cdd596c556bb2ded0f2037c260", // v1.6.3 + arm64: "813a4cd40f6740bd9623a40884a78f14960c6bd3794391693a165f2ca71c90e3", }, non_tls: { - amd64: "a9f1842e3d7f3d38c143dbe8ffe1948e6c8173cd04da072d9f9d128bb400844a", // v0.13.7 + amd64: "f0a8bb49ce5480744f8c836af2abd5f311e918efef5b36b4cce7521d7b9dffe6", // v0.14.0 }, };
src/cleanup.ts+3 −1 modified@@ -81,7 +81,9 @@ import { isGithubHosted } from "./tls-inspect"; } var disable_sudo = process.env.STATE_disableSudo; - if (disable_sudo !== "true") { + var disable_sudo_and_containers = process.env.STATE_disableSudoAndContainers; + + if (disable_sudo !== "true" && disable_sudo_and_containers !== "true") { try { var journalLog = cp.execSync("sudo journalctl -u agent.service --lines=1000", { encoding: "utf8",
src/install-agent.ts+2 −2 modified@@ -25,15 +25,15 @@ export async function installAgent( if (isTLS) { downloadPath = await tc.downloadTool( - `https://packages.stepsecurity.io/github-hosted/harden-runner_1.4.2_linux_${variant}.tar.gz` + `https://packages.stepsecurity.io/github-hosted/harden-runner_1.6.3_linux_${variant}.tar.gz` ); } else { if (variant === "arm64") { console.log(ARM64_RUNNER_MESSAGE); return false; } downloadPath = await tc.downloadTool( - "https://github.com/step-security/agent/releases/download/v0.13.7/agent_0.13.7_linux_amd64.tar.gz", + "https://github.com/step-security/agent/releases/download/v0.14.0/agent_0.14.0_linux_amd64.tar.gz", undefined, auth );
src/interfaces.ts+2 −0 modified@@ -8,6 +8,7 @@ export interface Configuration { egress_policy: string; disable_telemetry: boolean; disable_sudo: boolean; + disable_sudo_and_containers: boolean; disable_file_monitoring: boolean; is_github_hosted: boolean; private: string; @@ -20,6 +21,7 @@ export interface PolicyResponse { policyName?: string; allowed_endpoints?: string[]; disable_sudo?: boolean; + disable_sudo_and_containers?: boolean; disable_file_monitoring?: boolean; disable_telemetry?: boolean; egress_policy?: string;
src/policy-utils.test.ts+2 −0 modified@@ -36,6 +36,7 @@ test("merge configs", async () => { egress_policy: "audit", disable_telemetry: false, disable_sudo: false, + disable_sudo_and_containers: false, disable_file_monitoring: false, private: "true", is_github_hosted: true, @@ -62,6 +63,7 @@ test("merge configs", async () => { egress_policy: "audit", disable_telemetry: false, disable_sudo: false, + disable_sudo_and_containers: false, disable_file_monitoring: false, private: "true", is_github_hosted: true,
src/policy-utils.ts+4 −0 modified@@ -56,6 +56,10 @@ export function mergeConfigs( localConfig.disable_sudo = remoteConfig.disable_sudo; } + if (remoteConfig.disable_sudo_and_containers !== undefined) { + localConfig.disable_sudo_and_containers = remoteConfig.disable_sudo_and_containers; + } + if (remoteConfig.disable_file_monitoring !== undefined) { localConfig.disable_file_monitoring = remoteConfig.disable_file_monitoring; }
src/setup.ts+8 −0 modified@@ -62,6 +62,7 @@ interface MonitorResponse { egress_policy: core.getInput("egress-policy"), disable_telemetry: core.getBooleanInput("disable-telemetry"), disable_sudo: core.getBooleanInput("disable-sudo"), + disable_sudo_and_containers: core.getBooleanInput("disable-sudo-and-containers"), disable_file_monitoring: core.getBooleanInput("disable-file-monitoring"), private: context?.payload?.repository?.private || false, is_github_hosted: isGithubHosted(), @@ -92,6 +93,13 @@ interface MonitorResponse { encoding: "utf8", } ); + fs.appendFileSync( + process.env.GITHUB_STATE, + `disableSudoAndContainers=${confg.disable_sudo_and_containers}${EOL}`, + { + encoding: "utf8", + } + ); core.info(`[!] Current Configuration: \n${JSON.stringify(confg)}\n`); if (confg.egress_policy !== "audit" && confg.egress_policy !== "block") {
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-mxr3-8whj-j74rghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-32955ghsaADVISORY
- github.com/step-security/harden-runner/commit/0634a2670c59f64b4a01f0f96f84700a4088b9f0nvdWEB
- github.com/step-security/harden-runner/releases/tag/v2.12.0nvdWEB
- github.com/step-security/harden-runner/security/advisories/GHSA-mxr3-8whj-j74rnvdWEB
News mentions
0No linked articles in our index yet.