A soft hyphen reopened a bug PHP closed in 2012
CVE-2024-4577 is a patch bypass of a 12-year-old PHP-CGI flaw. The 2012 fix sanitized the input. Windows then helpfully rewrote a soft hyphen back into a real one, after the check, and handed the attacker their command-line argument anyway.
The 2012 version of this bug, CVE-2012-1823, let an attacker smuggle command-line arguments into PHP running as CGI by abusing how query strings without an = sign got passed to the php-cgi binary. PHP fixed it. The fix checked the input and rejected the dangerous patterns. For twelve years, that was the end of it.
CVE-2024-4577 is the same attack walking back through a door the fix didn’t know was there. Orange Tsai of DEVCORE, who titled the writeup “Make PHP-CGI Argument Injection Great Again,” noticed that Windows performs a “Best-Fit” character conversion when mapping Unicode to certain legacy code pages. A soft hyphen, 0xAD, isn’t a regular hyphen and sails past PHP’s sanitization. But when the string crosses into the Windows code-page layer, Best-Fit helpfully converts that soft hyphen into a plain -. The check ran on the safe version of the input. The dangerous version is what php-cgi actually received. The attacker gets to inject -d options like allow_url_include=1 and auto_prepend_file=php://input, and that’s unauthenticated remote code execution, CVSS 9.8.
Why this is the interesting failure
Most patch bypasses are about a fix that was too narrow, one code path closed while a sibling stayed open. This one is more instructive, because the 2012 fix was correct for the input it inspected. It failed because the input changed after it was inspected. The sanitization and the consumption of the data were separated by an encoding transformation nobody in the loop accounted for.
That’s a general lesson worth carrying past PHP. Any time you validate a string and then hand it to a downstream component that re-encodes, normalizes, or “helpfully” rewrites it, your validation is checking a value that no longer exists by the time it matters. Unicode normalization, locale code-page mapping, URL decoding that happens twice, a library that trims or substitutes characters: each is a place where “I already sanitized this” quietly becomes false. The defensive posture the bug argues for is to validate at the point of use, against the exact bytes the sensitive function will see, not at the point of entry against a version that’s still going to be transformed.
The exposure is wider and narrower than it looks
Narrower, because this only bites a specific configuration: PHP running in CGI mode on Windows, with a vulnerable code page. The conditions DEVCORE confirmed as default-exploitable were Windows systems set to Traditional Chinese (code page 950), Simplified Chinese (936), or Japanese (932) locales. If you run PHP via PHP-FPM, or mod_php, or on Linux, this specific vector doesn’t apply, and plenty of modern stacks moved off php-cgi years ago.
Wider, because of one product: XAMPP. The popular Windows AMP bundle ships configurations that expose the PHP executable in the CGI directory by default, which means a lot of Windows machines are running vulnerable php-cgi without anyone having made a deliberate decision to. Those are exactly the boxes that don’t get tracked: developer laptops, internal test servers, a forgotten demo instance, an appliance that embedded XAMPP. Because the PHP team couldn’t guarantee the safety of every locale and configuration, the official guidance and the fix treated Windows php-cgi as broadly at risk rather than carving out “safe” locales. Assume you’re exposed if the configuration exists, rather than betting your locale isn’t on the list.
It was weaponized in roughly two days
This is the part that removes any room for a slow response. PHP disclosed the bug and shipped fixed builds on June 6, 2024. By June 8, defenders were already seeing exploitation, and within about 48 hours of disclosure the flaw was folded into the TellYouThePass ransomware campaign. CISA added it to the Known Exploited Vulnerabilities catalog on June 12 with a July 3 deadline and the ransomware flag set. The TellYouThePass operators used the RCE to invoke mshta.exe against an attacker-hosted HTA file, running VBScript that loaded a .NET build of the ransomware straight into memory. Public proof-of-concept exploits, including one from watchTowr, were available almost immediately, which is what turns a clever encoding trick into a commodity mass-exploitation event. Exploitation continued well into 2025, broadening past the initially-targeted regions.
What to do
- Patch to PHP 8.3.8, 8.2.20, or 8.1.29 or later. Those builds fix the Best-Fit handling. If your PHP rides inside another product (XAMPP, a vendor appliance, a packaged web app), update through that vendor and confirm the bundled PHP version, because that’s where the unpatched copies hide.
- Find your
php-cgion Windows. The real risk is the instances you don’t know about. Inventory Windows hosts for XAMPP and any Apache configuration that maps requests tophp-cgi.exe. A forgotten dev box running XAMPP is the classic victim here. - If you can’t patch immediately, get off CGI mode. Migrating to PHP-FPM or
mod_php, or blocking access to the CGI endpoint, removes the vector. CGI-mode PHP is a legacy deployment style with little reason to persist. - Hunt for the post-exploitation pattern. Web server processes spawning
mshta.exe,cmd.exe, orpowershell.exe, andphp-cgirequests containing encoded soft hyphens orauto_prepend_file/allow_url_includeparameters, are exploitation indicators.
The reframe is the bit to keep. A patch is only as good as its assumption that the data it inspected is the data that gets used. CVE-2024-4577 is twelve years of safety undone by an operating system silently rewriting one character downstream of the check. When you validate input, validate it where it’s consumed, against what the consumer actually sees, because everything in between is allowed to change it. We track the patch-bypass entries in the KEV catalog with particular attention, because a bypass means a control someone already trusted has quietly stopped working.
Sources
- CISA Known Exploited Vulnerabilities Catalog
- NVD CVE-2024-4577 — 2024-06-09
- Orange Tsai / DEVCORE: Make PHP-CGI Argument Injection Great Again — 2024-06
- Qualys ThreatPROTECT: PHP CGI Argument Injection (CVE-2024-4577) — 2024-06-10
- Imperva: CVE-2024-4577 weaponized to distribute TellYouThePass ransomware — 2024-06
- Help Net Security: PHP command injection flaw exploited to deliver ransomware — 2024-06-13
Share
Related field notes
-
22,000 servers ransomed in days: the CyberPanel control-panel wipeout
Two CVSS-10 pre-auth RCEs in CyberPanel let the PSAUX ransomware crew encrypt roughly 22,000 internet-exposed servers in late October 2024. Hosting control panels run as root and face the internet by design, which is exactly why one bug becomes a fleet-wide event.
-
The same handful of mechanisms account for most of the catalog
After the marquee bugs, Tier 1's remaining entries, DotNetNuke, ForgeRock, BQE, Sophos, Tomcat, Citrix ShareFile, SAP, Quest, Atlassian Crowd, Exim, Cisco ASA, Office, don't introduce new lessons. They confirm the few recurring mechanisms behind nearly every exploited vulnerability.
-
Five hours from public PoC to live exploitation on your monitoring server
CVE-2024-6670 is an unauthenticated SQL injection in WhatsUp Gold. The exploit went public at 5pm UTC; Trend Micro saw the first real attack by 10pm. The tool that watches your whole network became the way in.
One email, every weekday morning.
You're in. Check your inbox.