October 20 was a rough day for the internet’s plumbing. Two critical problems surfaced within hours of each other, and both sit in technology nearly every organization runs: the PHP engine behind WordPress, Drupal, Magento, and countless custom applications, and the TLS certificate trust that keeps HTTPS honest. Neither can wait for next month’s maintenance window.
PHP2Shell: CVE-2026-109618 and CVE-2026-109619
Overview:
Two remote code execution vulnerabilities in the PHP engine, nicknamed PHP2Shell, let an unauthenticated attacker run code on a web server with a crafted HTTP request. Both carry a CVSS v4.0 score of 9.2. The attack lands before your application code ever runs. A fully patched WordPress or Magento install offers zero protection if the PHP underneath it is vulnerable.
The vulnerable code goes back to PHP 5.4, released in 2012. PHP shipped fixes on October 21 in PHP 8.5.12, 8.4.27, 8.3.36, and 8.2.35. PHP 8.1 and older are out of support and will not get an official fix. Palo Alto Networks Unit 42 counts more than 22.6 million internet-exposed instances that are potentially vulnerable.
This one is bad. Technical details leaked online on October 20, a day before the coordinated release. watchTowr confirmed working remote code execution from the leaked material, and early attack activity was reported the morning of October 21, before most teams had a patched package to install.
What It Is:
Both bugs follow the same pattern. A fatal error, usually PHP hitting its memory_limit, interrupts the engine in the middle of an operation. PHP then treats the half-finished state as valid. That is a use-after-free (CWE-416), and attackers can shape it into controlled memory corruption.
- CVE-2026-109618 (out-of-memory corruption): During request parsing, PHP marks certain internal state as ready before all of its memory allocations finish. If an allocation fails, that state is never rolled back, and cleanup routines process uninitialized memory as if it were real data. Red Hat confirms this works against mod_php in its default configuration and against PHP-FPM through application-stage paths.
- CVE-2026-109619 (stale global state): PHP keeps some error-handling, object, and extension state at the process level that points to memory owned by a single request. A fatal error can stop cleanup before that state resets, and the next request handled by the same worker uses it after the memory has been freed. PHP’s advisory confirms two exploitable paths: fatal error backtraces on PHP 8.5, which are enabled by default, and session upload-progress handling.
There is also a nasty side effect. The researchers showed that the session upload-progress path can return freed worker memory to the client inside the PHPSESSID cookie. If that sounds like Heartbleed, it should. An attacker can read chunks of server memory without ever achieving code execution.
Calif found multiple RCE paths in August and started coordinated disclosure on August 11. Wiz Research reported the issues independently on August 24. Researchers have demonstrated pre-authentication RCE against WordPress, Drupal, Joomla, and Magento 2.4.9.
Why It’s Dangerous:
- Any PHP script is an entry point. The attacker needs no login, no vulnerable plugin, and no misconfiguration. Every installation that serves web requests is in scope, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP, and LiteSpeed. mod_php carries the most risk.
- Code execution means your secrets are gone. The attacker runs as the web server user and can read
wp-config.php,.envfiles, and Magento’sapp/etc/env.php, then dump databases, plant webshells, and pivot inward. - Memory disclosure works even when RCE fails. Worker memory can hold session tokens, API keys, and database credentials.
- Shared hosting multiplies the blast radius. One compromised site can become a foothold against every neighbor on the box.
- Legacy PHP has no official fix. The forgotten intranet app running PHP 7.4 and the vendor appliance with an embedded PHP 8.0 stay vulnerable until someone migrates them or a vendor backports a fix.
Assura’s Recommendations:
- Find every PHP install. Include containers, appliances, and anything your developers stood up and forgot. The CLI and PHP-FPM can load different
php.inifiles, so check the binary your web server actually uses.
php -v
which -a php
ls /usr/sbin/php-fpm* /usr/bin/php* 2>/dev/null
php-fpm8.4 -i | grep -E 'memory_limit|session.upload_progress.enabled|fatal_error_backtraces'
docker ps --format '{{.Names}} {{.Image}}' | grep -i php
docker exec <container> php -v
- Patch now. Target PHP 8.5.12, 8.4.27, 8.3.36, or 8.2.35. Distributions backport fixes, so your version string may not match upstream. Check your distribution’s advisory for the fixed package version, and restart PHP-FPM and the web server afterward. A patched binary on disk does nothing for workers that are still running.
# Debian/Ubuntu
sudo apt update
apt list --upgradable 2>/dev/null | grep -i php
sudo apt install --only-upgrade 'php8.*'
sudo systemctl restart php8.4-fpm apache2
# RHEL/Alma/Rocky
sudo dnf update 'php*'
sudo systemctl restart php-fpm httpd
# cPanel/CloudLinux (fixed ea-php and alt-php packages are published)
sudo yum update 'ea-php*' 'alt-php*'
- Rebuild container images. Don’t assume your base image tag was rebuilt. Run
php -vinside the running container to confirm. - If you cannot patch today, apply PHP’s interim mitigations. Set these in
php.ini, the PHP-FPM pool, or the web server configuration. Never useini_set()or.user.ini, because PHP’s advisory says those do not work for these settings. These only block the confirmed paths, so treat them as a stopgap.
; php.ini
session.upload_progress.enabled = 0
fatal_error_backtraces = 0 ; PHP 8.5 only, enabled by default
; PHP-FPM pool, e.g. /etc/php/8.4/fpm/pool.d/www.conf
pm.max_requests = 1 ; kills worker reuse, costs performance
php_admin_value[session.upload_progress.enabled] = 0
- Remove per-request INI overrides. PHP lists a warning from these settings as one of the confirmed triggers. Look for
php_valueandphp_flagin.htaccessfiles, and forPHP_VALUEpassed from nginx.
grep -rnE 'php_(value|flag)' /var/www --include=.htaccess
grep -rn 'PHP_VALUE' /etc/nginx/
- Be careful with
memory_limit = -1. Some vendors recommend it because CVE-2026-109618 relies on PHP hitting its memory limit. Without a cgroup or container memory cap, though, you trade an RCE for a trivial denial of service. Only use it with a per-worker memory cap in place. - Turn on WAF rules, but don’t call it fixed. Cloudflare and Imunify360 have shipped rules for the circulating exploit. They buy time and nothing more.
- Isolate legacy PHP. Pull anything on PHP 8.1 or older off the internet or put it behind authentication, then schedule the migration you have been putting off.
- Hunt on exposed servers. Treat any internet-facing PHP server that was unpatched after October 20 as a hunting target. If you find new PHP files you can’t explain, rotate every secret stored on that host.
find /var/www -type f -name '*.php' -newermt '2026-10-20'
Detection Signals:
- Bursts of
Allowed memory size of ... bytes exhaustedfatal errors, especially from unauthenticated routes or a single source IP - PHP-FPM workers dying with
exited on signal 11 (SIGSEGV) - Oversized or malformed
multipart/form-dataPOSTs containing thePHP_SESSION_UPLOAD_PROGRESSfield, particularly to endpoints that never accept uploads - Responses setting abnormally long
PHPSESSIDvalues or values containing non-alphanumeric bytes - Web server processes (
php-fpm,php-cgi,apache2,httpd,w3wp.exe) spawningsh,bash,curl,wget,nc,python,perl,cmd.exe, orpowershell.exe - New or modified PHP files in web roots, upload directories, or cache directories
grep -E 'Allowed memory size of [0-9]+ bytes exhausted' /var/log/php*-fpm.log /var/log/apache2/error.log /var/log/nginx/error.log
grep -E 'exited on signal 11' /var/log/php*-fpm.log
eMudhra (emSign) Intermediate CA Key Compromise
Overview:
The private keys for eight intermediate certificate authorities run by eMudhra, the Indian CA that sells under the emSign brand, are compromised. Six of the intermediates could issue TLS certificates, and two could issue code-signing certificates. The keys were generated with insufficient randomness, so anyone can recover a private key from the public certificate. Scott Helme reproduced the key recovery and found it takes milliseconds.
With one of those keys, an attacker can mint a valid certificate for any domain: yours, your bank’s, or Microsoft’s. Any client that still trusts the intermediate will accept the forged certificate.
Browsers moved fast. Chrome and Firefox blocked the certificates on October 17, Apple on October 19, and Microsoft on October 20. eMudhra revoked all eight. The company says none of the intermediates issued end-entity certificates and only one was ever used in production. Google found no TLS certificates chaining to the six TLS intermediates in Certificate Transparency logs before it blocked them. As of October 21, there is no public evidence of malicious use.
That covers browsers. Everything else is where the risk is.
What Happened:
On October 17, a researcher identified as Wayne reported the compromise to Apple, Google, Microsoft, Mozilla, and eMudhra. He proved it by signing a message with each of the eight private keys. All eight certificates were created in April 2025, and eMudhra attributes the weak keys to a flaw in its key generation ceremony. Eight weak keys from one ceremony is a process failure, not bad luck. It’s the digital equivalent of a locksmith cutting eight master keys with a butter knife.
The six TLS intermediates were issued by emSign Root TLS CA – G3, which chains to emSign ECC Root CA – G3:
- Domain validated: EM DV TLS CA – G3B (eMudhra BV, Netherlands) and EM DV TLS CA – G3C (eMudhra Inc, United States)
- Organization validated: EM OV TLS CA – G3B and EM OV TLS CA – G3C
- Extended validation: EM EV TLS CA – G3B and EM EV TLS CA – G3C
- Code signing: two intermediates, including EM OV CS CA – G3B
The root programs are not stopping at the intermediates. Mozilla shipped an NSS update that removes the eMudhra root. Chrome’s removal of the root is expected to reach all devices that rely on the Chrome Root Store on October 27.
Why It’s Dangerous:
- Non-browser clients don’t get OneCRL or CRLSets. Python’s certifi, curl’s CA bundle, PHP’s Composer ca-bundle, Node.js, Java, and anything baked into a container image carry their own trust stores. Many of them never check revocation.
- Server-to-server traffic is the quiet target. API integrations, update channels, payment callbacks, and internal tooling rarely have a human watching for certificate warnings. A forged certificate there would go unnoticed.
- Security appliances have their own trust stores. TLS inspection proxies, secure web gateways, load balancers, and firewalls validate upstream certificates against bundles that update on the vendor’s schedule, not yours.
- Expect outages. Any site or vendor still using an emSign G3 certificate will break in Chrome once the root removal lands. Some of your suppliers will learn this the hard way.
- Treat code signed under these intermediates as suspect. Chrome didn’t need to block the two code-signing intermediates, because its TLS verifier won’t build a path through them. Software signed under them is a separate problem and still deserves scrutiny.
Assura’s Recommendations:
- Update operating system trust stores. Fixed packages include Ubuntu
20260816ubuntu0.<release>.1, Debian20250419~deb12u2and20250419+deb13u1, Fedora2026.2.92_v9.0.319, Alpine20261020-r0, and Archca-certificates-mozilla 3.131.1-1.
# Debian/Ubuntu
sudo apt update && sudo apt install --only-upgrade ca-certificates
sudo update-ca-certificates --fresh
ls /etc/ssl/certs | grep -i emsign
# RHEL/Fedora/Alma/Rocky
sudo dnf update ca-certificates
sudo update-ca-trust
trust list | grep -i -A2 emsign
# Alpine
apk upgrade ca-certificates && update-ca-certificates
- Update application-bundled trust stores. This is the step most teams will miss. Fixed versions include certifi 2026.10.19, the curl CA bundle dated 2026-10-20, Composer ca-bundle 1.6.0 and 1.4.16, Homebrew ca-certificates 2026-09-25_1, and cloudflared 2026.10.2. Cloudflare has also released fixed WARP and 1.1.1.1 clients.
pip install --upgrade 'certifi>=2026.10.19'
python -c "import certifi; print(certifi.__version__)"
composer update composer/ca-bundle
brew upgrade ca-certificates
keytool -list -cacerts -storepass changeit | grep -i emsign
- Rebuild and redeploy container images. Images freeze the trust store at build time. An updated host does nothing for the containers running on it.
- Check Windows systems that don’t get Microsoft’s automatic updates. On air-gapped or restricted machines, download the certificates from the disclosure site and push them through Group Policy: Computer Configuration > Policies > Windows Settings > Security Settings > Public Key Policies > Untrusted Certificates.
Get-ChildItem Cert:\LocalMachine\Root, Cert:\LocalMachine\CA |
Where-Object { $_.Subject -match 'emSign|eMudhra|EM (DV|OV|EV) TLS CA' } |
Format-List Subject, Thumbprint, NotAfter
Get-ChildItem Cert:\LocalMachine\Disallowed |
Where-Object { $_.Subject -match 'EM (DV|OV|EV) TLS CA' }
- Inventory your own certificates. Search crt.sh for your domains and look for any issuer containing emSign or eMudhra. If you find one, replace it with a certificate from another CA before October 27.
openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts </dev/null 2>/dev/null | grep -E '^ *[0-9]+ s:| i:'
- Push your security vendors. Ask your firewall, proxy, and load balancer vendors when their trust bundles will drop these intermediates, and ask key SaaS vendors whether they use emSign certificates.
- Use the published fingerprints. Take the SHA-256 fingerprints and public keys from the researcher’s disclosure site. Don’t retype them from a blog post, including this one.
Detection Signals:
- Any TLS session where the server certificate’s issuer matches one of the six TLS intermediates. TLS 1.3 encrypts certificates in transit, so passive sensors only see this for TLS 1.2 and earlier unless you decrypt.
- Any Certificate Transparency entry for your domains issued by these intermediates
- Binaries whose Authenticode signer certificate was issued by an eMudhra G3 code-signing intermediate
# Zeek
zcat x509.*.log.gz | zeek-cut ts certificate.subject certificate.issuer | grep -E 'EM (DV|OV|EV) TLS CA - G3[BC]'
# Suricata
alert tls any any -> any any (msg:"ASSURA Cert issued by compromised eMudhra intermediate"; flow:established; tls.cert_issuer; pcre:"/CN=EM (DV|OV|EV) TLS CA - G3[BC]/"; classtype:bad-unknown; sid:9100001; rev:1;)
# PowerShell: check a signed binary
(Get-AuthenticodeSignature .\file.exe).SignerCertificate.Issuer
What Assura’s SOC is Doing for Our Clients:
If you’re an Assura client, our Offensive Security and SOC are collaborating on these issues. Here is what that looks like in practice:
- Vulnerability Management-as-a-Service: We are conducting out-of-cycle scans of client environments to identify whether these issues are present. Clients with assets affected by one or both of these issues will be contacted with a list of affected assets.
- Huntress: We are watching for PHP and web server processes spawning shells, download utilities, and reconnaissance tools on Windows and Linux endpoints, along with webshell drops in web roots. That is the post-exploitation pattern PHP2Shell produces.
- SentinelOne Singularity: With authorization, we can use application inventory to identify hosts running unpatched PHP builds and flagging them to your team. We are also running Deep Visibility hunts for suspicious PHP process lineage and new PHP files written after October 20.
- Stellar Cyber Open XDR: We are correlating web server and WAF logs for bursts of memory-exhaustion fatal errors and oversized multipart requests from the same sources. Where we have network sensor coverage, we are also alerting on TLS sessions that present certificates issued by any of the six compromised eMudhra intermediates.
- Certificate exposure: We are checking client-facing domains against Certificate Transparency logs for any certificate that chains to the eMudhra G3 hierarchy, and we will contact you directly if we find one.
Detection is not a substitute for patching. We will catch exploitation attempts and the activity that follows them, but the fix for PHP2Shell is a new PHP build and the fix for eMudhra is an updated trust store.
References:
- NVD: CVE-2026-109618
- NVD: CVE-2026-109619
- PHP Security Advisory GHSA-w8hw-w9fx-j79w
- PHP Security Advisory GHSA-6wmf-4rv5-p3rp
- PHP 8.5.12 Release and PHP 8.4.27 Release
- Red Hat: CVE-2026-109618 and CVE-2026-109619
- Wiz Research: PHP2Shell
- Huntress: PHP2Shell Rapid Response
- Unit 42 Threat Brief
- Sansec: PHP2Shell
- Datadog Security Labs: PHP2Shell Detection and Remediation
- Researcher Disclosure: eMudhra Intermediate CA Compromise
- Google: Protecting Chrome and Android Users from Compromised eMudhra Intermediate CA Certificates
- Cloudflare: 8 eMudhra Certificates Are Compromised
- Scott Helme: Eight Bits of Trust
- Ars Technica: The Internet Goes on High Alert After Discovery of 8 Compromised TLS Certs
If you’re an Assura client, reach out to your Virtual ISO or Concierge. Otherwise, contact us via the form on our website.