Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-46420

CVE-2026-46420: setup-php GitHub Action RCE Vulnerability

CVE-2026-46420 is a command injection RCE vulnerability in the setup-php GitHub Action that allows attackers to execute arbitrary commands on runners. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-46420 Overview

CVE-2026-46420 is a command injection vulnerability [CWE-78] affecting shivammathur/setup-php, a widely used GitHub Action that configures PHP with extensions, php.ini settings, coverage drivers, and tools. Versions from 2.25.0 through 2.37.0 resolve the PHP version from repository-controlled files including .php-version, composer.lock (via platform-overrides.php), and composer.json (via config.platform.php). The action fails to sufficiently constrain these values before embedding them into generated shell or PowerShell setup scripts. Attackers who influence repository contents can inject commands executed on the GitHub Actions runner. The issue is fixed in version 2.37.1.

Critical Impact

Workflows using triggers such as pull_request_target that check out attacker-controlled contents before invoking setup-php can execute arbitrary commands on the runner, exposing repository secrets and workflow tokens.

Affected Products

  • shivammathur/setup-php GitHub Action versions 2.25.0 through 2.37.0
  • GitHub Actions workflows invoking setup-php after checking out untrusted content
  • CI/CD pipelines using pull_request_target or similar privileged triggers with setup-php

Discovery Timeline

  • 2026-07-17 - CVE-2026-46420 published to NVD
  • 2026-07-23 - Last updated in NVD database

Technical Details for CVE-2026-46420

Vulnerability Analysis

The setup-php action reads the desired PHP version from repository files rather than solely from the workflow input. When the workflow checks out attacker-controlled code before running the action, values from .php-version, composer.lock, or composer.json propagate into shell command strings without adequate escaping. The generated Bash or PowerShell setup script then interprets injected metacharacters as commands. This is a classic OS command injection pattern where untrusted input reaches a shell interpreter unsanitized.

Root Cause

The action concatenates version and extension identifiers directly into command strings executed by bash on Linux/macOS or PowerShell on Windows. Inputs such as ini_values and extensions were passed through without shell-safe escaping. The upstream fix introduces utils.sanitizeShellInput and utils.escapeForShell helpers to neutralize shell metacharacters before interpolation.

Attack Vector

An attacker submits a pull request that modifies .php-version, composer.json, or composer.lock to embed shell metacharacters within the PHP version string. When a maintainer's workflow uses pull_request_target and checks out the pull request head prior to invoking shivammathur/setup-php, the malicious value flows into the generated setup script. Execution occurs under the runner's identity with access to GITHUB_TOKEN and any secrets exposed to the job.

typescript
// Patch excerpt: src/install.ts (version 2.37.1)
  const filename = os + (await utils.scriptExtension(os));
  const script_path = path.join(__dirname, '../src/scripts', filename);
  const run_path = script_path.replace(os, 'run');
- const extension_csv: string = await utils.getInput('extensions', false);
+ const extension_csv: string = utils.sanitizeShellInput(
+   await utils.getInput('extensions', false),
+   true
+ );
  const ini_values_csv: string = await utils.getInput('ini-values', false);
  const coverage_driver: string = await utils.getInput('coverage', false);
  const tools_csv: string = await utils.getInput('tools', false);

// Patch excerpt: src/config.ts (version 2.37.1)
  });
  return (
    'echo "' +
-   ini_values.join('\n') +
+   ini_values.map(v => utils.escapeForShell(v, 'linux')).join('\n') +
    '" | sudo tee -a "${pecl_file:-${ini_file[@]}}" >/dev/null 2>&1' +
    script
  );
// Source: https://github.com/shivammathur/setup-php/commit/eeef37e059fb5368a5bc8ed8ce45ff54bd39b80b

The patch wraps user-controllable inputs with sanitizeShellInput and applies per-platform shell escaping to ini_values before concatenation into the echo command piped to sudo tee.

Detection Methods for CVE-2026-46420

Indicators of Compromise

  • Unexpected outbound network connections from github.com-hosted or self-hosted runners during setup-php steps
  • Modifications to .php-version, composer.json, or composer.lock in pull requests that contain shell metacharacters such as `, $(, ;, or &&
  • Runner logs showing setup-php failures or unusual subprocess spawns during PHP version resolution
  • Access or exfiltration of GITHUB_TOKEN, secrets, or environment variables from within a setup-php job

Detection Strategies

  • Audit repositories for workflows that combine pull_request_target with actions/checkout of the pull request head followed by shivammathur/setup-php
  • Scan pull request diffs for suspicious content in .php-version, composer.jsonconfig.platform.php, and composer.lockplatform-overrides.php
  • Enforce dependency pinning checks that flag shivammathur/setup-php references below version 2.37.1

Monitoring Recommendations

  • Enable GitHub Actions audit logs and forward runner telemetry to a centralized data lake for query-based hunting
  • Alert on child processes spawned by setup-php that are not part of expected PHP installation flows
  • Track outbound DNS and HTTP requests from runners during setup-php execution to detect data exfiltration

How to Mitigate CVE-2026-46420

Immediate Actions Required

  • Upgrade all workflow references from shivammathur/setup-php@v2 or earlier pins to shivammathur/setup-php@2.37.1 or a commit SHA at or after the fix
  • Review pull_request_target workflows and remove checkout of untrusted pull request contents before privileged action execution
  • Rotate any secrets that may have been exposed to workflows using vulnerable versions with untrusted contributor input

Patch Information

The fix is available in setup-php release 2.37.1. Details are documented in GitHub Security Advisory GHSA-pqwm-q9pv-ph8r and the remediation commit. Pin the action to the release tag or the specific commit SHA to ensure integrity.

Workarounds

  • Replace pull_request_target with pull_request where privileged secrets are not required
  • Explicitly set the php-version input in the workflow rather than allowing resolution from repository files
  • Remove or ignore .php-version, platform-overrides.php, and config.platform.php when the source is untrusted
bash
# Pin setup-php to the patched version in .github/workflows/ci.yml
- name: Setup PHP
  uses: shivammathur/setup-php@2.37.1
  with:
    php-version: '8.3'
    extensions: mbstring, intl
    ini-values: memory_limit=512M

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.