This week delivered the kind of security news that makes every self-hosted administrator open a second terminal: an emergency PHP release, public exploit discussion before the planned disclosure window, and a separate certificate-authority incident that forced browsers and operating systems to distrust parts of an HTTPS chain.
These events are related by urgency, not by root cause. PHP was an application-runtime vulnerability. The eMudhra incident was a public-key infrastructure and trust-store problem. A Cloudflare proxy, a reverse proxy, or a valid-looking padlock did not remove either responsibility.
PHP Apps Already in This Homelab Series
This is not an abstract warning for people running a bare PHP binary. Several of the self-hosted applications covered on Foss Engineer depend on PHP directly or commonly run as PHP web applications:
| Application | Existing guide | What to check now |
|---|---|---|
| Nextcloud | Nextcloud Native | The Nextcloud server image, PHP-FPM version, background jobs, and any separate web container |
| WordPress | WordPress with Docker | PHP runtime, WordPress core, plugins, themes, upload handling, and exposed admin paths |
| Mautic | Mautic | PHP/Symfony image, workers, cron containers, plugins, and public tracking/forms |
| Wallabag | Wallabag | The Wallabag image, PHP dependencies, database credentials, and public API |
| Grav | Grav CMS | PHP version, flat-file permissions, admin path, and plugin updates |
The exact deployment may differ between these projects, but the operational question is the same: which container or host process handles the HTTP request? Updating a database, reverse proxy, or application container that does not contain PHP does not patch the PHP runtime. Check the active version inside the serving container and redeploy the image containing it.
What Happened to PHP?
On October 21, the PHP project published a critical security advisory for two vulnerabilities:
CVE-2026-109618, an out-of-memory corruption issue;CVE-2026-109619, a stale global-state issue.
The official advisory describes both as potential unauthenticated remote code execution. The affected surface is broader than a single CMS: it includes PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, and LiteSpeed deployments that serve requests through vulnerable PHP versions.
The fixed branches released on October 21 were:
| Branch | Fixed version |
|---|---|
| PHP 8.5 | 8.5.12 |
| PHP 8.4 | 8.4.27 |
| PHP 8.3 | 8.3.36 |
| PHP 8.2 | 8.2.35 |
The official PHP advisory
recommends updating immediately. It also recommends setting session.upload_progress.enabled=0 until the next regular bugfix release as an additional mitigation for one attack path.
Why Was It Called “PHP2Shell”?
The nickname came from the practical consequence: a remote attacker could potentially turn a request into code execution on a vulnerable PHP server. The drama intensified because vulnerability details and CVE references circulated before the planned coordinated release. Administrators were warned that working exploit tooling could appear very quickly after the patches became public.
The useful lesson is not that PHP is uniquely unmaintainable. It is that a runtime used by a large percentage of the web creates a huge patching coordination problem. A WordPress, Drupal, Joomla, MediaWiki, Laravel, or custom PHP site inherits the urgency of the runtime underneath it.
What Happened to SSL Certificates?
The second event involved eMudhra Global TLS intermediate certificate authorities . On October 17, an independent researcher reported that the private keys associated with eight intermediate CAs were cryptographically weak. eMudhra revoked the eight intermediates on October 18 and browser/platform vendors began blocking the affected chains.
The important distinction is between an intermediate CA and a website certificate. An intermediate CA can issue end-entity certificates. If its private key is recoverable, an attacker may be able to create a convincing certificate for another domain. That is why the response involved browser root programs, operating-system trust stores, language runtimes, and embedded CA bundles.
According to eMudhra’s incident statement, the affected intermediates did not issue end-entity certificates and there was no evidence of infrastructure compromise or data breach. That does not make the event harmless: any client that still trusts the compromised chain needed updated trust information.
Apple's advisory says Apple began blocking the affected certificates on October 19 and later added the affected ECC root to its block. Sectigo's advisory explains that its cross-certificates for the affected CAs were revoked as part of the response.
Why This Matters in a Homelab
There are two different patch paths:
- Inbound PHP service: update the PHP runtime or application image, then restart/redeploy the PHP worker pool.
- Outbound TLS client: update the operating-system or application trust store in every container, VM, CLI tool, firmware image, and embedded runtime that makes HTTPS connections.
Updating the certificate on your website does not patch PHP. Updating a browser does not update the CA bundle inside an old Docker image. Renewing a Let’s Encrypt certificate does not fix a container that still trusts a revoked or distrusted CA.
A Practical PHP Checklist
Start by identifying where PHP is actually running:
php -v
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
docker compose config --images
For each PHP service:
docker exec <php-container> php -v
docker inspect <php-container> --format '{{.Config.Image}}'
Then update the image or base package to a release containing the fixed PHP branch. Do not only update the web application if the PHP runtime is supplied by a separate FPM container. Rebuild and redeploy pinned images where possible:
docker compose pull <php-service>
docker compose up -d --force-recreate <php-service>
docker compose logs --tail=100 <php-service>
If you build the image yourself, update the PHP base image and rebuild it. Check the runtime inside the resulting container rather than trusting the tag:
docker build --pull -t my-php-app:patched .
docker run --rm my-php-app:patched php -v
For the interim PHP mitigation, confirm the setting in the active SAPI rather than only editing a file that PHP does not load:
docker exec <php-container> php -i | grep '^session.upload_progress.enabled'
The exact configuration path depends on the image and SAPI. Do not copy a mitigation into production without checking its compatibility with your application.
A Practical Certificate Checklist
First inspect the certificate actually served by a public endpoint:
openssl s_client \
-connect example.com:443 \
-servername example.com \
-showcerts </dev/null
Inspect the leaf certificate and issuer:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -fingerprint -sha256
Also test from a normal HTTP client:
curl -Iv https://example.com/
If the endpoint uses an affected eMudhra chain, follow your certificate provider’s reissue instructions. Do not rotate every certificate blindly: identify the issuer and complete chain first, then check the current browser, OS, and CA vendor guidance.
For containers and Linux hosts, update the trust store through the base distribution and rebuild long-lived images:
# Debian/Ubuntu-based image or host
apt-get update && apt-get install --only-upgrade ca-certificates
# Alpine-based image or host
apk update && apk upgrade ca-certificates
The exact package command belongs in the Dockerfile or image build process rather than being an undocumented one-off change inside a running container. A restart alone does not update a baked-in CA bundle; rebuild and redeploy when the trust store is part of the image.
Remember non-browser clients: curl, Git, Java, Go binaries, Python bundles, mobile SDKs, firmware, IoT devices, and application images may carry their own trust store or update on a different schedule.
Cloudflare Does Not Remove the Need to Patch
Cloudflare can terminate TLS at the edge and apply WAF rules. That helps reduce exposure, but it does not update PHP on your origin. If the origin is reachable through another hostname, an open port, an internal route, or a misconfigured firewall, the origin still needs the PHP fix.
Likewise, a Cloudflare-issued certificate on the visitor-facing edge does not tell you which certificate your origin uses or which CA bundle your origin containers trust for outbound requests.
What I Would Do First
For a small homelab, I would use this order:
- Inventory PHP containers, VMs, and direct host installs.
- Patch or temporarily isolate anything serving PHP requests.
- Rebuild images that include PHP or
ca-certificates. - Inspect public certificate chains and identify any eMudhra dependency.
- Update host and container trust stores.
- Test with
openssl,curl, and the application-specific client. - Review logs for unexpected PHP worker restarts, new files, outbound connections, and authentication anomalies.
- Record the fixed image digest, package version, certificate issuer, and validation date.
This is also a good argument for immutable image tags, a small service inventory, automated update notifications, and backups that are tested before an emergency. “The container restarted” is not the same as “the vulnerable runtime was replaced.”
FAQ
Do all PHP sites need to be taken offline?
Do I need to update WordPress or Drupal too?
Does putting PHP behind Cloudflare solve PHP2Shell?
Was every eMudhra certificate compromised?
Does a valid padlock prove my homelab is safe?
Why must I rebuild Docker images for certificate fixes?
What should I record after remediation?
What am I doing to reduce the attack surface of this blog homelab?
I am reducing the number of internet-facing services instead of keeping every experiment permanently online. One example is sunsetting Commento, the self-hosted commenting service used by this Hugo blog. Before stopping it, I exported a private JSON archive containing the 22 comments, 13 page records, 6 commenter profiles, 2 votes, domain metadata, timestamps, parent/thread IDs, rendered HTML, moderation state, deletion state, and sticky-comment metadata.
The archive intentionally excludes password hashes, sessions, owner credentials, moderator credentials, and secrets. It is stored with restrictive file permissions and is not committed to the public repository. The email addresses inside the commenter metadata make it private even though the comments were displayed publicly. This leaves the comments available for a later static rendering or carefully planned migration without keeping the Commento service and PostgreSQL database exposed.
Other practical reductions follow the same pattern: remove unused containers and images, close unused ports, keep only the public services that need to be public, update runtimes and base images, and keep a tested backup before deleting a service.
Conclusion
The PHP emergency and the eMudhra certificate incident exposed different layers of the same operational reality: software is not secure because it was deployed once, and HTTPS is not a permanent status badge.
Patch the runtime. Update the trust stores. Verify the chain. Check the alternate paths. Keep evidence of what changed. That is the practical response for a homelab, a VPS, or a production platform built from the same containers.
Comments