Run npx php2shell-checker@latest <url> to check the PHP version a site advertises, or --local [--php PATH] on the server for the binary that serves it. It prints OK, VULNERABLE or UNKNOWN, exits 0, 1 or 3, and supports --json for scripts and CI. Read-only, open source, Apache-2.0.
On this page
Install and run
No installation needed — npx fetches the latest version. You need Node.js 20 or newer.
# Check the PHP version a website advertises
npx php2shell-checker@latest https://example.com
# Check a PHP binary on this machine (the accurate way)
npx php2shell-checker@latest --local
npx php2shell-checker@latest --local --php /usr/sbin/php-fpm8.3
Prefer a global install?
npm install -g php2shell-checker
php2shell-checker https://example.com
Options
| Option | Description |
|---|---|
<url> |
Site to check. http:// and https:// only. |
--local |
Check a local PHP binary by running it with -v. |
--php PATH |
Binary to check with --local (default: php on your PATH). Point it at your PHP-FPM binary to check the web runtime. |
--timeout SECONDS |
Network timeout for URL checks, 1–60 (default 10). |
--json |
Machine-readable output. |
--version |
Print the checker’s version. |
-h, --help |
Show usage. |
Exit codes
| Code | Result | Meaning |
|---|---|---|
0 |
OK |
Stable patch release above the vulnerable cut-off for its branch. |
1 |
VULNERABLE |
At or below the cut-off for its branch. |
3 |
UNKNOWN |
No version found, an untracked branch, or a pre-release build. Not the same as patched. |
2 |
— | Invalid arguments. |
JSON output
npx php2shell-checker@latest --local --json
{"patch_status":"vulnerable","php_version":"8.3.31","reason":"PHP 8.3.31","exit_code":1}
patch_status is ok, vulnerable or unknown. Human-readable notes go to stderr, so --json output on stdout is always clean.
How it works
URL mode sends one HEAD request (falling back to GET only if the server answers 405 or 501), reads the Server and X-Powered-By response headers, and compares any PHP version it finds with the vulnerable ranges. It doesn’t follow redirects, doesn’t read the response body, and never sends a payload.
Local mode runs the binary with -v and parses the version line.
If it sees several versions, it reports the worst one, so an OK-looking banner can’t hide a vulnerable one.
Limitations
- Most production servers hide their PHP version, so URL mode often returns
UNKNOWN. Use--localon the server. - Distribution packages (Ubuntu, Debian, RHEL…) backport fixes without changing the version number, so a version check can say
VULNERABLEfor a patched package. Confirm with the package changelog. OKis a version comparison. It confirms you’re on a fixed release, not that every other part of your server is secure.
Use it in CI
Stop vulnerable images from shipping. This GitHub Actions job builds your image and fails if the PHP inside it is vulnerable — it wraps php in a tiny script so the checker can call it through Docker:
name: php2shell
on: [push, pull_request]
jobs:
php-version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Build image
run: docker build -t app:ci .
- name: Fail if PHP in the image is vulnerable
run: |
printf '#!/bin/sh\nexec docker run --rm --entrypoint php app:ci "$@"\n' > php-in-image
chmod +x php-in-image
npx -y php2shell-checker@latest --local --php ./php-in-image
Exit code 1 fails the job; 3 (unknown) fails too, which is the safe default for CI.
Monitor your own site
A simple cron job can warn you if a site you run starts advertising a vulnerable PHP version (only useful if your server exposes the version):
# crontab -e — check every morning at 07:00 and email on anything but OK
0 7 * * * npx -y php2shell-checker@latest https://example.com >/dev/null 2>&1 || echo "PHP2Shell check failed for example.com" | mail -s "PHP2Shell alert" [email protected]
Source and licence
The checker is open source under the Apache-2.0 licence: GitHub · npm. Issues and suggestions are welcome on GitHub. Only use it on systems you own or are authorised to assess.