Quick Answer: The php2shell checker tool is a lightweight Node.js utility developed by OpenAI (phpcheck.js) that detects whether a local PHP binary or remote website runs a PHP patch version vulnerable to php2shell attacks. It evaluates HTTP response headers or local CLI outputs against embedded version thresholds, returning standardized exit codes (0 for OK, 1 for VULNERABLE, 3 for UNKNOWN).

Exposing legacy PHP versions on public web servers remains a leading initial access vector for threat actors targeting enterprise web applications. When security teams evaluate infrastructure exposure, passive identification must be immediate and scriptable. OpenAI released a lightweight auditing utility specifically to tackle this issue across unpatched PHP environments. Integrating the php2shell checker tool into your auditing routines lets you rapidly locate exposed runtime versions before adversaries convert remote code execution flaws into interactive reverse shells.

1. Understanding the PHP2Shell Risk Profile

Unpatched web runtimes represent a massive target surface. The php2shell threat vectors specifically exploit underlying interpreter flaws to gain arbitrary command execution on target server nodes. When an attacker delivers a targeted payload to a system running an affected PHP release, the process can be hijacked to spawn an outbound interactive shell, bypassing traditional perimeter firewalls.

Many organizations operate sprawling infrastructures where shadow IT or legacy microservices run outdated PHP branches. According to W3Techs Web Technology Surveys, PHP powers over 76% of websites with known server-side programming languages. A substantial fraction of these deployments rely on end-of-life branches such as PHP 7.4 or early 8.x releases. Passive version detection allows DevSecOps teams to triage these assets at scale without triggering aggressive Intrusion Prevention System (IPS) alerts that full vulnerability scans often generate.

That said, relying purely on banner grabbing introduces operational nuances you must handle carefully. This next part trips people up every time.

2. Setting Up and Deploying the PHP2Shell Checker Tool

The checker exists as a single Node.js script named phpcheck.js designed for minimal runtime dependencies. You can invoke it directly via the Node CLI or install it through OpenAI Codex as a skill module ($skill-installer install both skills from https://github.com/openai/php2shell-checker).

To audit a target application directly from your terminal, pass the target URL or specify the local execution flag:

# Direct remote website evaluation
node phpcheck.js "https://example.com"

# Direct local binary audit
node phpcheck.js --local

If you are wondering how to use open ai php2shell checker tool in automated testing environments, the repository includes a standalone test suite (phpcheck.test.js) executed via node --test phpcheck.test.js. This suite spins up internal mock HTTP servers and synthetic binary executables, allowing you to validate scanner logic within locked-down build pipelines without hitting external endpoints or requiring local PHP installs.

Here is where it gets interesting: the tool handles connection handshakes with surgical precision to minimize network footprint.

3. How Detection Works: Remote Header Analysis vs Local CLI Inspections

The underlying engine in phpcheck.js employs two distinct detection paths depending on whether you run a remote probe or local binary evaluation.

When probing a URL, the script sends an HTTP HEAD request to query the target web server's HTTP response headers. Specifically, it parses the X-Powered-By header and the Server header string to isolate version strings matching patterns like PHP/8.1.12. To preserve bandwidth and reduce server logs, the tool refrains from downloading full response bodies. If the target server responds with HTTP 405 Method Not Allowed or 501 Not Implemented, phpcheck.js automatically falls back to an HTTP GET request.

When you execute the tool locally using the --local flag, it skips the network layer entirely. Instead, it executes php -v in the underlying shell environment and captures the standard output banner.

Once the version string is isolated, the tool compares it against an embedded map of known stable patch cutoffs. If the detected release sits at or below the cutoff threshold for that major/minor branch, the tool flags the target as vulnerable.

This dual approach provides distinct operational trade-offs depending on your network visibility and access level.

4. Comparing Remote URL Probes and Local Server Audits

Selecting between remote header checks (phpcheck-url) and local environment checks (phpcheck-server) depends heavily on your compliance mandate and infrastructure context.

Feature / MetricRemote URL Scan (phpcheck-url)Local CLI Audit (phpcheck-server)
Primary MechanismHTTP HEAD / GET Header InspectionExecution of php -v binary output
Target HeadersX-Powered-By, ServerN/A (Direct OS binary invocation)
Network FootprintLow (Single HTTP handshake)Zero network traffic
Bypass ExposureVulnerable to proxy stripping/spoofingImmune to HTTP banner obfuscation
Exit Status ReliabilityHigh false-UNKNOWN rate if headers hiddenHigh precision for local runtime

While remote scanning offers zero-friction discovery across thousands of endpoints, it suffers from severe visibility gaps when web servers hide their software banners. This brings us directly to the inherent limitations of passive banner analysis.

5. Automating CI/CD Workflows with JSON Output and Exit Codes

Integrating security checks into deployment pipelines requires predictable status signals rather than human-readable text logs. The utility implements structured exit codes alongside optional JSON formatting:

  • Exit Code 0 (OK): The detected PHP patch version is strictly above the embedded safety cutoff for its release branch.
  • Exit Code 1 (VULNERABLE): The runtime is confirmed to be at or below the vulnerable threshold.
  • Exit Code 3 (UNKNOWN): No version header was exposed, the response was unparseable, or an unrecognized prerelease build was encountered.
  • Exit Code 2: Invalid CLI arguments were provided.

By appending the --json flag, phpcheck.js emits a clean JSON payload containing the patch_status key:

{
  "patch_status": "vulnerable",
  "version": "8.0.12",
  "target": "https://example.com"
}

Security teams can feed this output directly into Security Information and Event Management (SIEM) indexers or block CI/CD build stages when patch_status returns vulnerable.

Most people stop here — don't. Understanding why an UNKNOWN status occurs is crucial for preventing silent security failures.

6. Navigating Practical Blind Spots: Header Obfuscation and Enterprise Backports

Here is a counter-intuitive finding that catches many DevSecOps engineers off guard: an OK result from a remote banner check does not guarantee complete protection, and an UNKNOWN result does not necessarily mean you are unpatched.

Hardened production systems routinely obscure runtime details. Best-practice security guides recommend disabling expose_php = Off in php.ini or configuring reverse proxies like Nginx using fastcgi_hide_header X-Powered-By. When these controls are active, the remote php2shell checker tool returns an UNKNOWN status (exit code 3). In experienced red-teaming scenarios, an UNKNOWN endpoint is often a high-priority target because header stripping frequently masks unmonitored legacy infrastructure.

Furthermore, enterprise Linux distributions such as Red Hat Enterprise Linux (RHEL), Debian, and Ubuntu frequently backport security fixes into older package releases without bumping the main upstream version string. For instance, a Debian server might report PHP 7.4.3 via HTTP headers—which falls below upstream patch cutoffs—yet carry downstream distribution patches that completely neutralize the remote code execution vector.

When auditing enterprise systems, never rely solely on passive HTTP response headers. Combine remote probes with local binary checks or internal package manager queries (dpkg -l or rpm -qa) to establish ground truth.

Frequently Asked Questions

What is the primary function of the php2shell checker tool?

The php2shell checker tool evaluates web servers and local binaries to determine if they run PHP versions vulnerable to php2shell shell execution attacks. It inspects HTTP response headers or local binary output and compares version numbers against known fixed patch cutoffs.

How to check php version for vulnerabilities without exposing headers on public endpoints?

To check your PHP version safely without exposing server headers publicly, execute the audit locally on the host system using node phpcheck.js --local or query your package manager directly. Alternatively, run passive scans internally behind your reverse proxy prior to header stripping rules.

Why does the checker utility return an UNKNOWN status?

An UNKNOWN status (Exit Code 3) occurs when the target server suppresses the X-Powered-By or Server HTTP headers, returns unexpected response codes, or runs a custom/prerelease build that does not match known release branch patterns in the tool's embedded database.


Passive version auditing remains an invaluable first line of defense when auditing enterprise PHP deployments. To protect your infrastructure, combine passive banner inspection with strict configuration management and continuous runtime auditing. Execute the php2shell checker tool across your perimeter endpoints today, pay close attention to any UNKNOWN responses, and verify backported patches with host-level package management tools. For deeper security hardening, read our breakdown of PHP Server Hardening Best Practices and explore our guide on Securing Reverse Proxies Against Header Leakage next.