On October 20 and 21, three different layers of the internet's foundations broke at the same time.
PHP, the language behind roughly 70% of websites, shipped emergency fixes for two flaws that let anyone run code on a server without logging in. An Indian certificate authority turned out to have signing keys so weak that one of them was literally the number 4. And LiteLLM, a popular open source proxy whose whole job is to hold your AI API keys, pushed a release that stole them.
Around those three, the same week brought a fresh Node.js security release, a cloud platform announcing it would shut down after its second breach in two months, and active attacks on home Plex servers. TechCrunch's headline on Wednesday was simply "The internet is having a very bad cybersecurity day."
Each story is worth looking at on its own, because they fail in different ways. But they share one thing that I think matters more than any of the individual bugs.
1. PHP2Shell
On October 21, PHP released 8.5.12, 8.4.27, 8.3.36 and 8.2.35 to fix two vulnerabilities:
- CVE-2026-109618, where running out of memory at the wrong moment leaves request data half-initialized and cleanup treats it as valid
- CVE-2026-109619, where state from one request survives after its memory is freed and gets picked up by the next request on the same worker
Both are rated 9.2. PHP's advisory says every installation serving web requests is at risk, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed, and that on mod_php an unauthenticated request "can trigger the attack before any application code runs." According to Wiz, "Every PHP version released in the last decade is affected by at least one of these vulnerabilities," and it demonstrated remote code execution against the stock WordPress, Drupal and Joomla container images. Because the bug is in PHP itself, it doesn't matter how carefully your application was written.
The bugs were found with AI. Calif, working under OpenAI's "Patch the Planet" program, used GPT-5.6 Sol. Wiz used its own agent alongside Gemini 4 Argon and GPT-5.6 Sol. OpenAI's Codex Security team reported further attack paths. Wiz is open about the other side of that coin: LLMs "can help adapt an exploit to different PHP versions, configurations and memory layouts," which used to be the hard part.
So far this sounds like a success story: AI-assisted researchers found a bug class that has been in PHP for over a decade, reported it, and it got fixed. The PHP Foundation's own account is much less flattering, and to its credit, the Foundation wrote it itself.
- The bug wasn't new to PHP. A core developer had already found signs of the out-of-memory problem while fixing something else. Work on a fix would "stall and restart repeatedly over months" while the security team argued over approaches with limited resources. The Foundation calls this "a structural failure, caused by both the security team's decision process and its lack of resources."
- August 11: Calif and OpenAI independently reported the same root cause, now as a working RCE. Wiz followed on August 24, and OpenAI reported more paths on September 18.
- October 20, ~15:00 UTC: the two CVE IDs leaked onto forums and social media, with a wrong release time and a wrong score of 10.0.
- October 20, ~19:30 UTC: PHP published its pre-announcement early and pulled the release forward a day.
- October 20, ~20:00 UTC: Calif accidentally published a video of its proof of concept running against several targets. Copies spread, and the Foundation says it "reportedly accelerated" exploit development.
- October 20, ~23:00 UTC: mitigation advice given privately to critical infrastructure providers may also have leaked.
- October 21, 07:41 UTC: Chainguard published container images with the fix built in, more than six hours before the coordinated release. Anyone who wanted to could diff the binaries to find the patch.
- October 21, ~14:00 UTC: the patches went out.
Reports on whether attackers got there first disagree. Patchstack recorded reports of active exploitation from hosting partners at 07:34 UTC on October 21 and said Cloudflare saw early attacks; at 13:57 UTC, its own telemetry showed only probing, with no hard evidence of breaches yet. The PHP Foundation says its security team inspected the appearing PoCs but "did not identify any functional exploits at the time of release/public disclosure." Those are different observations, not a basis for declaring that no working exploit had landed anywhere.
2. The certificate authority whose key was 4
On October 20, Mozilla's Dennis Jackson disclosed that private keys for eight intermediate certificates belonging to eMudhra, an Indian certificate authority, had been compromised.
"Compromised" usually means someone stole a key. That's not what happened here. Scott Helme looked at the certificates and found that the keys were tiny numbers. One of them, as The Register put it in a headline, "was the number 4." Others were 56, 115, 66, 155, 156, 230 and 237. A P-384 key should be a random 384-bit number. These fit in a single byte, and Helme recovered all of them in under a second.
Those keys could sign a certificate for any domain on the internet. And because they've been weak since the certificates were created in April 2025, there's no way to know whether anyone else noticed first. As Ian Carroll put it, "They are inherently weak single-byte keys that anyone can factor, and the issue cannot be contained." Helme's summary is the one I keep coming back to: "every certificate those CAs could ever issue, every client that trusted them, rested on eight bits."
The good news is that browsers have mostly handled it. Mozilla, Chrome and Apple have distrusted the certificates, and browsers also require Certificate Transparency, which makes a quiet forgery much harder. Cloudflare patched its own services before the public disclosure and says it saw no active exploitation.
The bad news is everything that isn't a browser. curl, Python, Node, Go and Java mostly trust whatever certificate bundle is on disk and don't check revocation or Certificate Transparency by default. Helme's forged certificates were accepted on Linux and macOS, and on Windows unless revocation checking was turned on. That covers CI pipelines, curl | sh installers, server-to-server API calls and IoT devices that will keep trusting these intermediates until 2039. Node.js's October 21 release removes them from its bundled store, and every other bundle needs the same update.
Cloudflare's advice for anyone who suddenly sees certificate errors is worth repeating: "It's important to not resolve these errors by disabling verification."
3. LiteLLM
LiteLLM is a proxy that sits between your application and a dozen LLM providers. To do that, it holds every one of your provider API keys.
On October 21, someone published a malicious litellm==1.107.0 to PyPI, and malicious images to Docker Hub and GitHub's container registry under the latest, main-latest and main-stable tags. According to LiteLLM's incident post, the PyPI package was live from 11:39 to 13:23 UTC and the Docker Hub images until 14:20.
Aikido's analysis shows the package dropped a .pth file that runs on every Python startup. It stole cloud credentials, SSH and GPG keys, Kubernetes and CI secrets, browser passwords, config files for AI tools like Claude, Cursor and Copilot, and LiteLLM's own database of provider keys. It also installed a backdoor that checks in with the attacker every hour and runs whatever Python it's sent.
LiteLLM's October 23 account, which supersedes its preliminary explanation, is a chain of ordinary failures:
- A master key for LiteLLM's Agent Platform was committed to a public repository on May 27 and was not revoked. On October 10, the attacker used it to read the Agent Platform API and extract a GitHub CLI OAuth token belonging to the organization's owner, then used CI workflows to steal two more maintainer tokens.
- Release permissions had been temporarily widened, allowing any two engineers to trigger and approve a release. LiteLLM notes that an organization owner could have relaxed or removed those restrictions anyway.
- The attacker used the owner token to disable branch protection, force-push a change that pointed the release at the lookalike repository,
Berri-AI/litellm, and dispatch the staging workflow. - A second maintainer's token approved the production gate. A third maintainer's token then deleted the production and staging workflow records.
Branch protection and approval gates were there. The attacker had an owner token that could change the rules, plus the maintainer tokens to make the release look routine.
If you installed an unpinned LiteLLM or pulled one of those Docker tags in that window, LiteLLM's advice is to treat the environment as compromised: pin to 1.106.2 or earlier, don't run pip inside the infected environment first (that starts Python, which runs the malware again), rebuild from scratch and rotate everything the host could reach.
The rest of the week
None of these happened on the 20th or 21st, but they belong to the same picture.
- Zeabur, a Taiwanese deployment platform, published its report on its second breach in two months on October 19. The attacker used a cluster admin token created in January 2024 with no expiry. It had been stored in plaintext in a config repository since January 20, 2026, and wasn't rotated after the August breach. The attacker read 3,218,965 environment variable records and 321,810 accounts, and more than 16 hours of activity on October 14 set off no alerts. Zeabur's wind-down starts December 1: shared services pause (with manual restarts for backups), dedicated-server renewals stop and servers shut down on their individual expiry dates; December 31 is the final cutoff, not a promise of service until then.
- PingCAP announced on October 19 that stolen service account credentials gave an attacker access to internal systems behind TiDB Cloud for almost a month, including customer contacts, contracts, billing data and source code.
- Plex2Shell, a four-bug chain in Plex Media Server, was patched in August. A public proof of concept went up on October 16, and attackers started using it the next day to install crypto miners and proxyware on home servers.
- BeyondTrust patched a Remote Support zero-day on October 8 that a suspected China-nexus group had been exploiting since late August.
What actually went wrong
It's tempting to read this week as a story about AI: AI found the PHP bugs and AI makes exploits easier to adapt. Both are true, and I don't think it's the main story.
Look at how long each problem existed before it caused trouble:
- PHP's out-of-memory bug was known inside the project, then fixing it stalled for months.
- eMudhra's keys were guessable for 17 months.
- Zeabur's admin token had been stored in plaintext since January 20, 2026, and survived a breach response.
- Plex2Shell had been patched for ten weeks when it was exploited.
Finding the bugs was the fast part. AI made it faster still: Wiz went from first bug to working WordPress RCE in two days. Everything after the finding was slow and fragile, and the way PHP's disclosure fell apart shows it. The process depended on several companies keeping a secret, and a leaked ID, an accidental video and an early container build were enough to blow it open in under 24 hours. The same goes for LiteLLM's release process, which depended on nobody collecting enough developer tokens, and for Zeabur, which depended on someone getting around to a rotation.
That's the lesson I'd take from Black October: the bottleneck in security is no longer finding bugs. It's everything humans have to do after they're found. AI is going to keep finding them faster, on both sides. Projects like PHP that run on a handful of volunteers and a small foundation can't absorb that, which is why the PHP Foundation ended its post asking companies and governments to fund its security work. I think they should.
What to do this week
- Update PHP everywhere. Not just your main server: containers, staging sites, old WordPress installs and anything that bundles PHP. If you're on 8.1 or older, you need a vendor backport or an upgrade. If you can't patch yet, PHP's advisory lists partial mitigations, but it's clear that they "do not make an installation safe." PHP's October 23 upload-progress warning also describes an RCE vector under an unusual combination: upload progress must still be enabled, and
session.serialize_handlermust be configured asphp_binaryorphp_serializeand then switched tophpat runtime withini_set()beforesession_start(). For that setup, PHP recommendssession.upload_progress.enabled=0until the next regular bugfix release; if you already disabled it, keep it disabled. Applications that never change the handler at runtime can keep upload progress enabled. - Update your CA bundles, then rebuild. That means OS
ca-certificates, Node, Python'scertifi, Java's cacerts and every container base image. A bundle that's frozen into an image you built last month still trusts eMudhra. On macOS, Apple's October 23 advisory distinguished automatic browser/framework blocks from some command-line tools using/etc/ssl/cert.pem, which could still accept affected chains; its update to that file was forthcoming at advisory time. Apple offers optional interim root-removal guidance, but it affects every tool using that file and can break legitimate chains. Verify through the application's actual TLS path, not a package version or a successful browser test alone. - Never fix a certificate error by turning off verification. If something breaks this week because it relied on an eMudhra certificate, that's the system working.
- Check for
litellm==1.107.0in lockfiles, virtual environments and running containers. If you find it, follow LiteLLM's steps and rotate every credential on that host, not just the AI keys. - Pin your dependencies and image tags.
latestis how a two-hour window on Docker Hub ends up in your production cluster. - Look for long-lived tokens. Zeabur's and LiteLLM's attackers both got in with credentials that worked for far longer than anyone needed them to. Expire them, scope them and keep them out of logs and config repos.
- Update Plex to 1.43.3.10861 or later if you self-host it. If an older server was internet-exposed, assume it may be compromised and follow Plex's assessment and cleanup guidance: check for persistence and other signs of compromise. If you find signs or cannot rule out compromise, rebuild from a clean installation without reusing the old Plex data directory, sign out all devices, change your Plex password and treat shares and stored credentials reachable by the Plex service account as potentially exposed.
Sources
- TechCrunch, The internet is having a very bad cybersecurity day
- PHP, Security advisory: Critical remote code execution vulnerabilities, update now
- The PHP Foundation, Today's PHP security release, and how we're strengthening PHP security
- Wiz, PHP2Shell: unauthenticated RCE in PHP
- TechCrunch, PHP Armageddon: OpenAI, Google's Wiz find ancient holes, panicking the internet
- Patchstack, Major security alert: PHP vulnerable to critical RCE, attacks ongoing
- Mozilla dev-security-policy, eMudhra intermediate key compromise
- Scott Helme, Eight bits of trust: eMudhra's CA keys cracked in milliseconds
- The Register, Indian certification authority eMudhra's private keys compromised; one of them was the number 4
- Cloudflare, eMudhra certificate compromise
- Node.js, October 2026 security releases
- LiteLLM, Security incident: October 21, 2026
- LiteLLM, Security incident: October 21, 2026 — attack chain (October 23)
- Aikido, LiteLLM compromised with infostealer and RAT
- Zeabur, October 2026 security incident
- PingCAP, Security update: October 2026
- The Hacker News, Hackers exploit Plex2Shell flaws
- BleepingComputer, BeyondTrust patches zero-day exploited in attacks since August