Research · Lokimesh Team · October 26, 2026

This Is Not Another PHP2Shell Article

Black October was a disclosure wave, not the start of the attacks. Patching closes the door. Decoys tell you who walked through while it was open.

We hope everybody had a good patching weekend.

We mean it. Somewhere, a sysadmin rebuilt a container image at 2 AM on Saturday because the base image still shipped a PHP version from 2022. Somewhere, a SOC analyst read the same advisory four times to work out whether "8.4.27" meant their distro package or upstream. Somewhere, a team took a public site offline because the regulator told them that was the safer option. If that was you, thank you. That work is real, and it is thankless.

You will not find another breakdown of the two CVEs here. Plenty of people have already written that one, and written it well. This piece is about what the weekend leaves out: the question patching cannot answer.

TL;DR Black October was mostly a disclosure wave. Many of the intrusions it revealed began weeks or months earlier, and PHP2Shell was being exploited before most defenders had heard of it. Patching closes the door. It does not tell you who walked through while it was open. That job belongs to a second, well-known control that too many programs still treat as optional: decoys placed where post-exploitation goes, so that whoever got in first trips an alarm the first time they look around.

What happened, in one paragraph

Between October 19 and 22, a cluster of serious disclosures landed at once, and the community called it "Black October". The headline item was PHP2Shell: two memory-safety flaws in PHP itself (CVE-2026-109618 and CVE-2026-109619, CVSS v4 9.2) that allow unauthenticated remote code execution as the web server account. They reach back to PHP 5.4, and PHP runs on roughly seven in ten websites whose server-side language is known. Around it came a CVSS 10.0 in GitLab, a remote code execution in Node.js's Brotli decoder, memory bugs in NGINX, an actively exploited flaw in Siemens software, and a poisoned LiteLLM release on PyPI. Several government sites went offline, and the UK NCSC advised taking unpatched systems offline if necessary.

That is the summary. Here is the part we want to talk about.

The clock started long before the label

"Black October" sounds like an attack that began on a Monday. Most of it was not. The week was when the accounting landed, not when the harm began.

Look at the PHP2Shell timeline:

  • 2024: a PHP core developer flags the out-of-memory error behind one of the flaws. It is never fixed.
  • August 2026: researchers using frontier AI models find the bugs independently and report them.
  • October 17: Amazon Threat Intelligence sees an exploitation attempt in its sensor telemetry. That is four days before disclosure.
  • October 20: details leak ahead of the coordinated release.
  • October 21: patches ship, and so does a separate session-handling flaw that the new releases do not fix.

The window opened four days before the advisory, and decoys saw it first.

And PHP2Shell was not unusual that week. The same disclosure window revealed a student-data theft that ran from May to September before anyone noticed, and stolen service credentials used inside a database vendor for a month. A firewall flaw patched in May was still being exploited by ransomware groups in October. Rapid7 measured an average of three days from disclosure to exploitation for severe vulnerabilities last quarter.

Put those together, and the honest description of your exposure is not "we patched within 48 hours". It is: there was a window, it opened before we knew it existed, and we do not know for certain who used it.

That is not a failure of your patch process. It is just how the timeline works when attackers can have an exploit before you have an advisory.

Patch-only is a race you lose at least once

None of this is an argument against patching. Patch everything, patch fast, and then patch the things you forgot were running PHP. But be honest about what patching is.

Patching is prevention, with a delay you do not control. Its clock starts at disclosure. The attacker's clock can start at discovery, at a leak, or at the first diff of a vendor's early build. For PHP2Shell the gap was at least four days, and it was reported by a well-instrumented cloud provider. In your environment, without that instrumentation, the gap is simply unknown.

Patching has edges. End-of-life PHP versions got source patches and no official binaries. A separate flaw remains open on fully patched releases until the next regular release. Every appliance vendor that bundles PHP has to ship its own fix on its own schedule. Every one of those edges is a place where the window stays open longer than your dashboard says.

The WAF is a bridge, not a fix. Cloudflare shipped protection hours before disclosure and said plainly that it does not replace patching. Attackers started mutating payloads to get around the rules. Perimeter filtering buys time. It does not tell you what happened before it was turned on.

So the patching weekend answers one question, "is the door closed now?", and leaves a second one open: "did anyone come in while it was open?"

The earliest signal came from decoys

Here is the detail in the PHP2Shell story that deserves more attention than it got.

The first public evidence of exploitation in the wild did not come from an endpoint agent or a SIEM rule written for these CVEs. No rule existed yet. It came from decoys. Amazon's early sighting came from its global network of sensors built to be attacked. watchTowr reported exploitation in the wild through its own decoy network. These are systems with no legitimate users, so any interaction with them is a signal.

That is the oldest idea in deception, and it worked exactly as designed: you do not need to know the vulnerability to see the attacker.

Internet-facing decoys told the world that PHP2Shell was being exploited. They cannot tell you whether one of your servers was among the victims. For that, you need the same idea pointed inward.

Where decoys belong after a week like this

Think about what an attacker does in the first ten minutes after remote code execution as the web server user. It does not depend on which CVE got them in. It is the same routine every time:

  1. Read the configuration. .env files, wp-config.php, framework settings: anything holding database or API credentials.
  2. Use what they found. Connect to the database, call the internal API, try the cloud keys.
  3. Look sideways. Scan the subnet the web tier sits in, find the admin panel, the jump host, the backup share.
  4. Settle in. Drop a web shell, add an account, set up persistence.

Every one of those steps is a place to put a tripwire, and none of them requires knowing about PHP2Shell in advance. Any CVE, same first ten minutes: put a decoy on each step.

  • Decoy credentials in the config files themselves. A database user or API key that no application uses. The first login attempt with it is an alert, and it tells you which server leaked it.
  • Decoy services in the web tier's network. A database, an admin panel or an internal API that nothing legitimate talks to. A connection to one is an alert.
  • Decoy accounts and shares one hop away. An admin account that does not exist in any runbook. A backup share that nobody mounts.

In Lokimesh these are breadcrumbs and decoys: inert credentials and configuration entries planted on real servers, leading to decoy services that nothing legitimate touches.

This is the same principle CISA wrote down in September in its guidance on cyber decoys: put them where legitimate users rarely or never go, and treat any interaction as a high-fidelity alert. Black October is just a very loud reminder of why.

The property that matters most this week is that decoys are CVE-agnostic. The tripwire that catches a PHP2Shell intruder reading credentials also catches the GitLab intruder, the Node.js intruder, and whichever intruder arrives through next month's disclosure. Your patching program has to start over with every advisory. Your decoys do not.

A note on AI, because someone will ask

Frontier AI models helped find these bugs, and that will not slow down. More bugs will surface faster, and exploits will follow faster too. If the disclosure pace keeps rising, a defense built only on "patch before they exploit" gets harder every quarter.

Decoys stand up better to that shift. An attacker, human or AI agent, who lands on a server still has to look around. It still reads the config file, tries the credential it found, and connects to the service that looks important. That behavior does not change when the exploit was written by a model. If anything, automated attackers are more thorough explorers, which means they find your tripwires sooner.

Monday morning, after the patches

If the weekend went well, here is a short list for the week:

  • Close the edges. Find PHP you do not manage directly: appliances, vendor containers, EOL versions. Track the session-handling flaw that the October 21 release did not fix.
  • Assume the window was used. Look for new or modified PHP files since October 17, unexpected outbound connections from web servers, and new accounts. Rotate any secret a web server could read.
  • Plant the tripwires. Put decoy credentials in the configs of your most exposed web servers, a decoy service in their subnet, and a decoy account one hop away. Wire every one of them to an alert that a person actually reads.
  • Measure the gap. Next time, record when exploitation started, when you patched, and when (or whether) you would have known. The last number is the one this weekend could not give you.

The real lesson of Black October

The lesson is not that PHP is broken or that October is cursed. It is that every serious program needs two controls, not one: prevention that closes the door as fast as possible, and detection that works even when the door was already open.

The patching weekend was the first control at work, and the people who did it deserve the credit. The second control is the one that would have told you, quietly and early, whether anyone got in before them.

Thanks to the PHP maintainers, a small team that shipped fixes for a large share of the internet under real pressure, and to everyone who spent this weekend patching.

Sources