php2shell-check
Fast, zero-dependency checker and remediation helper for the PHP2Shell remote code execution flaws — CVE-2026-109618 and CVE-2026-109619.
What this is: a defensive tool. It inspects systems you operate — the local PHP install, version strings, Dockerfiles/compose files, your own running containers, and your own logs — tells you whether you're affected, and gives you the exact steps to fix it. It sends no exploit traffic and cannot be aimed at a remote host. It is not an exploit and does not contain one.
Respond in 60 seconds
curl -sO https://raw.githubusercontent.com/SirjanSingh/shiny-php/main/php2shell_check.py
python3 php2shell_check.py check # Am I affected?
python3 php2shell_check.py harden # If so, exact fix for my OS
# Then update PHP to 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 and re-check.
The vulnerability
On 2026-10-21 the PHP project shipped emergency patches for two critical core RCE vulnerabilities, collectively nicknamed PHP2Shell:
| CVEs | CVE-2026-109618, CVE-2026-109619 |
| Severity | Critical — CVSS v4.0 9.2 |
| Affected | PHP 5.4 through 8.5 |
| Fixed in | 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
| Workaround | Disabling session.upload_progress blocks the confirmed path but is incomplete — patching is the only full fix |
PHP 5.x and 7.x are end-of-life and receive no official fix; affected servers on those branches must move to a supported, patched branch.
Install
Single file, no dependencies, Python 3.9+:
curl -O https://raw.githubusercontent.com/SirjanSingh/shiny-php/main/php2shell_check.py
chmod +x php2shell_check.py
Or install it as a command with pipx (or pip):
pipx install php2shell-check # from PyPI (once published)
# or straight from source, no release needed:
pipx install git+https://github.com/SirjanSingh/shiny-php
php2shell-check check
Maintainers: see RELEASING.md for the one-time PyPI Trusted-Publishing setup. Tagging
vX.Y.Zthen publishes automatically.
Usage
Check this machine
./php2shell_check.py check
PHP2Shell check (CVE-2026-109618, CVE-2026-109619, disclosed 2026-10-21)
/usr/bin/php
PHP 8.4.26 (cli) (built: Oct 1 2026 10:00:00) (NTS)
AFFECTED: PHP 8.4.26 is affected. Update to 8.4.27 or later on this branch.
Action required. Run `php2shell-check harden` for the exact upgrade steps.
Check a version string (no live PHP needed — great for CI / inventory)
./php2shell_check.py check --version 8.3.40
Machine-readable output
./php2shell_check.py check --json
Exit codes: 0 not affected · 1 affected · 2 couldn't determine. Drop it
straight into CI:
./php2shell_check.py check --json || echo "patch PHP before shipping"
Remediate
./php2shell_check.py harden # print exact upgrade + workaround steps
./php2shell_check.py harden --apply --conf-dir /etc/php/8.4/fpm/conf.d
harden detects your OS and prints the right package-manager commands. With
--apply it writes a drop-in ini that disables session.upload_progress — a
partial mitigation; it will still tell you to update PHP.
Scan logs for attack attempts
./php2shell_check.py scan-logs /var/log/apache2/error.log /var/log/modsec_audit.log
./php2shell_check.py scan-logs /var/log/nginx/access.log --json
Read-only. It flags attempts, not confirmed compromise, keying on indicators published by security vendors after disclosure:
| Indicator | Log type | Source |
|---|---|---|
PHP_SESSION_UPLOAD_PROGRESS in a request body |
WAF / ModSecurity / body | Splunk, Zafran |
Upload filename= with a <?php tag |
WAF / body | Splunk |
Serialized PHP object marker (O:.., a:..) in a body |
WAF / body | Splunk |
PHP Fatal error … Unknown on line 0 |
PHP / error log | Abstract Security |
Apache AH00052 child-exit |
Apache error log | Abstract Security |
| Repeated large POSTs from one source IP | access log (heuristic) | Bitdefender, Beazley |
Important: plain access logs almost never record request bodies, so a clean access-log scan is not an all-clear — the body/field indicators need a WAF/ModSecurity log. And patch PHP regardless; detection is not prevention. These are behavioral signals based on expected exploit behavior, not confirmed atomic IoCs — validate against your own logs.
Scan Docker images
./php2shell_check.py scan-docker # Dockerfiles/compose in cwd
./php2shell_check.py scan-docker path/to/Dockerfile compose.yml
./php2shell_check.py scan-docker --running # + your running containers
Reads PHP base-image tags. A pinned tag (php:8.3.10) is judged exactly; a
floating branch tag (php:8.4) is flagged as ambiguous (pin a patched tag),
and an end-of-life branch tag (php:8.1) is flagged affected outright.
Check a whole fleet (offline)
./php2shell_check.py check --inventory hosts.txt
hosts.txt is one label version per line — straight from your inventory /
Ansible facts, no network or SSH involved:
web01 8.3.10
web02=8.4.27
db01: 7.4.33
SARIF → GitHub code scanning
./php2shell_check.py check --sarif > results.sarif
./php2shell_check.py scan-logs /var/log/modsec_audit.log --sarif > results.sarif
Upload it so findings land in your repo's Security tab:
# .github/workflows/php2shell.yml
- run: python php2shell_check.py scan-docker --sarif > results.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
Why there's no remote "URL scan" mode
Some PHP2Shell tools send a crafted probe to a target URL to test it. This one deliberately doesn't. It only inspects systems you operate (local, inventory, your Dockerfiles, your containers, your logs), so you can't accidentally point it at a host you don't own, and running it is never itself an attack. If you want to check a server, run it on that server. Full reasoning in SECURITY.md.
Tests
python -m unittest discover tests
Sources
- The Hacker News — PHP emergency patches for PHP2Shell RCE
- Qualys — find, mitigate, and patch PHP2Shell
- DigitalOcean — Critical PHP RCE, patch now
- Patchstack — PHP major vulnerability alert 10/2026
Detection guidance:
- Splunk Research — PHP session upload progress detections
- Abstract Security — PHP2Shell log artifacts
- Bitdefender — PHP2Shell technical advisory
- Zafran — PHP2Shell everything you need to know
Version/fix data in this tool reflects the 2026-10-21 release. Always confirm against php.net for your exact branch.
License
MIT — see LICENSE.
Metadata
Release files for php2shell-check 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| php2shell_check-0.1.0.tar.gz | 17.3 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| php2shell_check-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 33.3 kB
Release files / php2shell_check-0.1.0.tar.gz
| Download URL | php2shell_check-0.1.0.tar.gz |
|---|---|
| Size | 17.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
37bfe464c6a50345cdf5c5980f66a2cdf1f8192a5178368add58adb1bb748711
|
|
BLAKE2b-256 checksum How to use checksums |
1edb99baa4ff8b134c7a0cc66bf5d96cab57ab7af4550eba74ca498d89b3b0d1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logRelease files / php2shell_check-0.1.0-py3-none-any.whl
| Download URL | php2shell_check-0.1.0-py3-none-any.whl |
|---|---|
| Size | 16.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b90ef8af68b861a74c2e8d938734b998fc364dfc5a1269840eb6a5b8d9e02626
|
|
BLAKE2b-256 checksum How to use checksums |
afde64e3e89216f03eb0aa644be8191ad8a748543fd8551aeea7eb5098e1363d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logSecurity for php2shell-check 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for php2shell_check-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.