Black October 2026: What Engineering Teams Should Know Before the Next One
What the October 2026 security disclosures actually were - LiteLLM, Node.js, PHP, GitLab, edge appliances, eMudhra - how far the sources explain each cause, and why type matters more than label.
TL;DR
- "Black October" is an informal label for a cluster of security disclosures and incidents, mostly between October 17 and 22, 2026. It is not one coordinated attack and not one vendor's name.
- The incidents are different in kind. Some are listed by CISA as known exploited (PHP, the Brotli flaw fixed in Node.js, several edge appliances), one is a malicious release (LiteLLM 1.107.0), one is a key-generation failure with no intrusion at all (eMudhra), and GitLab's CVE-2026-110264 is a disclosure that is not listed in CISA's Known Exploited Vulnerabilities (KEV) catalog as of November 12, 2026.
- Sorting each item by type is the whole skill. The label tells you nothing about what to do; the type tells you everything.
- The sources explain the cause unevenly. Only the two incidents that were not code bugs have a published account of the process that failed, and the best accounts of how the appliances were entered come from defenders rather than vendors.
- If you installed
litellm==1.107.0, patching is not enough. Assume the credentials that host could reach are exposed and rotate them.
This is an awareness post, not an incident-response runbook. If you are mid-incident, your own IR process comes first. The value of a month like this one is the chance to read it calmly: see how the incidents differed, and check your own exposure while nothing is on fire.
The companion post covers the work: the security patch drill, who owns it, and the pipeline best practices that decide how the next wave lands on you.
Last verified: November 12, 2026. Details may change as vendors update their advisories.
What "Black October" actually means
The name is informal. Wikipedia has an article on it created on October 24, and Halborn says the term was coined around October 22 in response to a wave of incidents. Counts differ: ScruteX counts 28 incidents, another roundup counts 14, and there is no formal rule for what is included.
ScruteX itself says the incidents "did not all happen at once", and it flagged that 12 of its 28 early reports contained errors. Early coverage was noisy. Other incidents were reported under the same label, but this post covers only the ones I could cross-check against primary sources.
The useful lesson is to stop treating every CVE in the news as a breach. Sort each item by type first, because the response differs.
| Type | What it means | Incidents here | Exploitation status |
|---|---|---|---|
| Compromised release pipeline | A legitimate-looking release contains malicious code | LiteLLM 1.107.0 | Malicious release published; maintainers advise assuming exfiltration if installed |
| Leaked credential | A secret committed and never revoked | LiteLLM (reported root cause) | Used by the attacker, per maintainers |
| Fresh flaw exploited fast | Patch published, exploitation follows within days | PHP2Shell | Confirmed exploited; on CISA KEV Oct 26 |
| Library flaw exploited, fixed in embedding products | An open-source component flaw that other products embed | Brotli CVE-2026-111497 (fixed in Node.js) | Listed in CISA KEV Oct 27; Node's own advisory is silent on exploitation |
| Old bug found late | A long-lived flaw discovered by new research | PHP2Shell (age is a claim from secondary reports) | See above |
| Edge appliance exploitation | Internet-facing access products used for initial access | BeyondTrust, Ivanti Connect Secure, Fortinet | Confirmed exploited; on CISA KEV |
| Disclosure only | Fixed, with no exploitation listed by CISA | GitLab CVE-2026-110264, Node.js's other nine CVEs | Not listed in CISA KEV as of Nov 12, 2026 |
| Trust-store and certificate issue | Weak CA keys, trust removed | eMudhra intermediate CAs | Vendor said no breach was found |
Several rows overlap, and some incidents fit more than one type. That is the point: the label tells you little, the type tells you what to do.
The right-hand column keeps referring to CISA KEV, so it is worth being precise about what that is. The Known Exploited Vulnerabilities catalog is a list the US Cybersecurity and Infrastructure Security Agency maintains of CVEs with evidence of exploitation in the wild. It is a filter on reality rather than on severity: CVSS tells you how bad a flaw could be, KEV tells you somebody is actually using it. That distinction does real work here. GitLab's flaw is CVSS 10.0 and not in KEV; the Fortinet path traversal is mid-severity and is in KEV, because attackers used it. Inclusion requires evidence, which keeps the catalog short enough to be a usable queue — and it is free, needs no account, and publishes JSON and CSV feeds you can diff on a schedule.
Incident 1: LiteLLM 1.107.0 (compromised release)
Type: malicious release, supply chain. Sources: the maintainers' incident post and attack chain write-up.
What happened. On October 21, 2026, a malicious litellm==1.107.0 was published to PyPI (all seven wheels, live from 11:39:51 to 13:23 UTC). Malicious Docker images were also published: Docker Hub tags v1.107.0, latest, main-latest and main-stable until 14:20 UTC, and GHCR tags until 13:51 UTC. The official git tag did not contain the malicious files, because the release was built from a lookalike repository.
The payload was a credential stealer plus a remote-code loader. The malicious files included cook.pth and sitecustomize.py, which run on any Python start in that environment, including running pip. The maintainers say that if 1.107.0 was ever installed on a host with outbound internet access, you should assume exfiltration succeeded. The enterprise private release was not affected.
Root cause, per the maintainers' October 23 post (which replaced an earlier theory about an internal deployment's logs):
- An admin key for an internal alpha service was committed to a public repository on May 27 and never revoked.
- On October 10 the attacker used it to obtain a GitHub organisation-owner CLI OAuth token.
- The attacker exfiltrated CI secrets and obtained two more maintainer tokens.
- The private release workflow was changed (a
source_ownerinput was added) so staging built from a lookalike fork. - The production gate was approved with another maintainer's token. The two-person trigger and approve rule had been relaxed earlier that week.
- Run records were deleted and history was force-pushed to hide the change.
The chain as a picture, because the gap in the middle is the part worth staring at:
flowchart TD K["May 27 - admin key for an internal alpha service committed to a public repo"] --> U["Key never revoked - still valid 4.5 months later"] U --> T["Oct 10 - key traded for a GitHub org-owner CLI OAuth token"] T --> S["CI secrets exfiltrated and two more maintainer tokens obtained"] S --> W["Release workflow gains a source_owner input so staging builds from a lookalike fork"] W --> G["Production gate approved using a second maintainer's token"] R["Two-person trigger-and-approve rule relaxed earlier that week"] -.-> G G --> P["Oct 21 - malicious litellm 1.107.0 on PyPI, Docker Hub and GHCR"] P --> H["Run records deleted and history force-pushed to hide the change"]
Every step after October 10 took hours. The step that made them possible took four and a half months of nobody revoking a key.
Who is affected. Anyone who installed litellm==1.107.0 or pulled the affected image tags in the windows above. Pinning 1.106.2 or any explicit earlier version is safe, according to the maintainers.
What to do (the maintainers' remediation advice):
- Delete the malicious files before running
pip, becausepipitself triggers them. - Kill the detached Python daemon holding
/tmp/remote_code_loader.lock. - Reinstall a pinned safe version and rebuild images and virtual environments.
- Rotate everything the host could reach: the cloud instance role, every provider key stored in the proxy database, master and virtual keys, the database password, and any secret in process environments.
- Check CloudTrail for use of the role from outside your infrastructure.
- Compare Docker digests. The compromised index digest is
sha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e.
The lesson. The maintainers' posts list no CVE, GHSA or OSV identifier. A malicious release may have no CVE, so "no CVE" does not mean "safe", and removing the package alone is not remediation.
Incident 2: Node.js October security release
Type: listed by CISA as known exploited (Brotli CVE only); the other nine CVEs are not in KEV as of November 12, 2026. Node's own advisory says nothing about exploitation in the wild. Sources: security release notes and v26.12.1.
What happened. On October 21, 2026, Node.js shipped fixes for ten CVEs. The headline is CVE-2026-111497, a Brotli decoder out-of-bounds write, rated High by Node.js. Per Node, attacker-supplied Brotli data decompressed with node:zlib can corrupt process memory, leading to a crash, memory disclosure or remote code execution. The fix is a cherry-pick of an upstream Brotli commit.
Three things are true at once: Node rates it High; CISA added CVE-2026-111497 to its KEV catalog on October 27, 2026 (six days after Node's release), as "Google Brotli Unchecked Return Value Vulnerability"; and one independent analyst had argued code execution is practically unreachable. CISA's description says a remote unauthenticated attacker can corrupt adjacent decoder state memory, disclose sensitive memory, cause denial of service, or potentially execute arbitrary code using a crafted Brotli-compressed stream. CISA's notes say it affects an open-source component that other products embed, and point to the upstream Brotli v1.2.1 release. The severity of the worst case is disputed, but exploitation is listed. Patch now.
Because the flaw is in Brotli itself, it also affects other software that embeds Brotli, not just Node.js. Check your other products and vendors, not only your Node.js version.
The same release fixes nine other CVEs (not listed in CISA KEV as of November 12, 2026), including:
- CVE-2026-105482:
dns.resolvetruncates names containing a NUL character (high). - CVE-2026-105483 and CVE-2026-106069: TLS certificate hostname bypass cases (high).
- CVE-2026-106072 (medium) and Permission Model bypasses (low).
It also lists a dependency update that removes the eMudhra intermediate CA from the bundled trust store (see Incident 6).
Who is affected. Node.js 22.x, 24.x and 26.x. Fixed in 22.23.4, 24.22.1 and 26.12.1. Node notes that end-of-life versions are always affected by a security release.
What to do. Upgrade to the fixed versions, including in base images. Pay particular attention to internet-facing services that decompress untrusted Brotli input.
Incident 3: PHP2Shell (PHP)
Type: confirmed exploited. Sources: the PHP announcement, CISA's critical vulnerabilities alert, CISA's KEV addition and a BleepingComputer report.
What happened. Two vulnerabilities, both CVSS v4.0 9.2 and both unauthenticated remote code execution:
- CVE-2026-109618: out-of-memory handling can leave partially initialised request data that cleanup treats as valid.
- CVE-2026-109619: remote code execution via stale request-owned global state reused by a later request on the same worker.
Exploitation. Security press reported honeypot hits within days. One report described shells launched from two IPs on October 24, which is a single-source figure. CISA added both CVEs to its KEV catalog on October 26, 2026.
Discovery (secondary reports only). Reports say AI-assisted research found the bugs (reported to PHP in August, with Wiz also reporting independently) and that the underlying bug is about 14 years old, "since 2012". PHP's own advisory does not confirm the age, so treat it as a claim. Some European government sites were reportedly shut down proactively as a precaution.
Who is affected. CISA lists PHP serving web requests, including Apache mod_php, PHP-FPM, php-cgi, FrankenPHP and LiteSpeed. Fixed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 (October 21). Official backports exist for the 7.4, 8.0 and 8.1 branches.
What to do. PHP's announcement says there are no complete mitigations: updating PHP itself is the fix. Updating WordPress plugins or Composer packages does not fix it. Check the PHP version inside every container image and host, not only the application's dependency files.
Incident 4: GitLab CVE-2026-110264
Type: disclosure. CVE-2026-110264 is not listed in CISA KEV as of November 12, 2026. GitLab's page says nothing about exploitation, and ScruteX said none was reported as of October 22. Source: the GitLab 19.5.1 patch release.
What happened. An integer overflow in the regular expression compiler; under certain conditions an unauthenticated user could execute arbitrary code on the server. CVSS 10.0. The fix is a patch to Ruby, not to GitLab code.
Who is affected. All versions from 7.0 before the fixed versions 18.11.13, 19.0.10, 19.1.9, 19.2.9, 19.3.6, 19.4.3 and 19.5.1. The page does not say when the bug was introduced. GitLab.com and GitLab Dedicated were already patched.
What to do. Official GitLab packages and container images include the fix. A self-compiled install or custom container image must also upgrade Ruby to 3.3.13, 3.4.12, 4.0.9 or later.
The lesson. A language-runtime flaw can surface inside a product you only think of as an application. Your inventory should include runtimes embedded in the tools you host.
Incident group 5: edge and remote-access appliances
Type: confirmed exploited. Every CVE below is in the CISA KEV catalog.
BeyondTrust Remote Support
CVE-2026-102764 is an authentication bypass in versions 26.2.3 and earlier. The patch is BT26-05-RS (patches exist for 24.3.1 and later; older self-hosted versions must upgrade first). It was added to KEV on October 16. CISA says actors are exploiting it for initial access, then persistence, privilege escalation and lateral movement. See CISA's alert.
CISA's recommended actions:
- Apply the patch.
- Limit external access and restrict admin interfaces to trusted networks.
- Do network and memory forensics.
- If compromise is suspected: isolate the appliance, hunt for unrecognised privileged sessions, scripts, log gaps and account or session-policy changes, rebuild from a known-good state, rotate every credential the appliance stored, revoke all support sessions, and review new MFA registrations on privileged accounts.
Ivanti Connect Secure
- CVE-2026-104935, authentication bypass by spoofing, added to KEV on October 13 (CISA).
- CVE-2026-111357 (missing authentication for a critical function) and CVE-2026-118527 (predictable numbers or identifiers), both added on October 30 (CISA).
Fortinet
CVE-2025-61624, a path traversal for which CISA lists "Multiple Products", was added to KEV on October 16 (CISA).
Separately, Palo Alto Unit 42 described PEERSTITCH, a memory-resident implant in FortiOS logging and VPN daemons. It leaves no file on disk and opens no port. The intrusion it describes began in September 2024 through a FortiManager appliance. Defenders must hunt volatile memory.
The lesson. Patching does not remove persistence an attacker already established. For appliances, treat patching as the first step of an investigation, not the last.
Incident 6: eMudhra intermediate CA keys
Type: key-generation failure and trust-store lifecycle. Not an intrusion. Sources: eMudhra's statement, Google's Chrome and Android notice, Kudelski Security's write-up and BleepingComputer on the second round of revocations.
What happened. The private keys of eight intermediate CA certificates operated by eMudhra, an Indian trust provider, could be recovered directly from the public certificates. A researcher reported this to Mozilla on October 17, 2026; Chrome and Firefox blocked the eight certificates within hours. A later report widened the set, bringing the total of affected intermediate CA certificates to 16. Node.js removed the eMudhra intermediate CA from its bundled trust store in the October 21 release.
Root cause, per eMudhra and the Mozilla incident reports. A script error during a single key ceremony on April 30, 2025 produced a second, weak set of keys alongside the good ones; because the labels were similar, the weak ones were picked for signing. The affected certificates used P-384 private keys whose values were smaller than 256 — one of them, reportedly, the number 4. A later account describes a custom Python script used to move private keys between HSMs, with the weak keys generated outside the HSM. The reports also state that eMudhra did not verify the strength of generated keys, nor that the key used for signing matched the one created in the HSM.
Scope. eMudhra says root keys are unaffected and that these intermediates issued no end-entity certificates. There is no evidence anyone exploited the weak keys, but they were public for roughly 17 months before being reported, so nobody can prove they were not. Treat "no breach was found" as what it says: eMudhra found no intrusion. The keys were still trivially recoverable. Help Net Security reports eMudhra will exit the global TLS certificate business.
What to do. Check what your own trust stores contain: base images, JVM and OS bundles, and anything that pins or bundles CAs. The broader lesson is that key generation needs verification as a step of its own — generating a key and checking that the key you generated is actually strong are two different controls, and only the first one was in place here.
How each one actually happened
A fair question about any week like this: do the sources explain the cause, or only the symptom? They vary a lot. Below is what each source actually claims, and how far I would trust it. Only LiteLLM and eMudhra have a published account of the human or process failure behind the flaw; the rest explain the code defect, and for the appliances the entry path comes from third-party forensics rather than the vendor.
| Incident | Stated cause | Who says so | How far to trust it |
|---|---|---|---|
| LiteLLM 1.107.0 | Admin key committed to a public repo in May and never revoked, then a relaxed release gate | Maintainers, in a public post-incident write-up | Strong. First-party, step by step, and they corrected an earlier theory |
| eMudhra CA keys | Script error in an HSM key-transfer ceremony; no verification of generated key strength | eMudhra and the Mozilla incident reports | Strong on the mechanism; the account shifted once, so read the latest |
| Brotli / Node.js | Decoder ignored a failed block switch on the fast path and kept appending into an 8-byte buffer | Upstream Brotli fix, Node's notes, Rapid7 | Good on the defect. Nobody has published the exploitation evidence CISA has |
| PHP2Shell | Two defects: OOM unwinding leaves partly initialised request data; request state outlives its memory | PHP's advisory and the two GHSA entries | Good on the defect. "14 years old" and "AI-assisted discovery" are secondary |
| GitLab / Onigmo | Repeat ID stored in a signed 16-bit field while counted as an int, so it wraps past 32,767 | Third-party accounts of GitLab's fix commit | Weak. I have not read the commit, and GitLab has not published preconditions |
| BeyondTrust Remote Support | Improper origin validation in an internal messaging component; spoofed messages do file operations | Vendor advisory summaries; entry path from Mandiant | Moderate. No vendor root-cause analysis published |
| Ivanti Connect Secure | A three-bug chain: spoofable auth signal, predictable upload path, then a root maintenance task | Volexity's forensic research | Moderate. Reconstructed from forensics, not from a patch diff |
| Fortinet CVE-2025-61624 | CLI command handlers do not confine file-path arguments to a base directory | Third-party summaries of Fortinet FG-IR-26-122 | Moderate, and note it needs an authenticated read-write admin first |
Three things stand out when you read the causes side by side rather than the headlines.
The two incidents with a real root-cause story are the two that were not code bugs. LiteLLM and eMudhra both published an account of how a process failed — an unrevoked secret, an unverified key ceremony. Vendors with a code defect publish the defect and stop there, which is their right, but it means you cannot learn process lessons from a CVE. You can only learn them from incidents where somebody chose to write up the process.
The appliance causes come from the defenders, not the vendors. The most useful accounts of how BeyondTrust and Ivanti were actually entered are Volexity's and Mandiant's incident research, not the advisories. Both describe exploitation that started well before disclosure: reporting puts the earliest BeyondTrust activity at August 29 with containment on September 28 and disclosure on October 15, and Ivanti exploitation around October 3 against an October 13 patch. That gap is the thing to plan for, because no patch cadence closes it. Only detection and credential hygiene do.
flowchart LR subgraph BT["BeyondTrust Remote Support"] B1["Aug 29 - exploitation begins"] --> B2["Sep 28 - vendor contains it"] --> B3["Oct 15 - public disclosure"] --> B4["Oct 16 - added to CISA KEV"] end subgraph IV["Ivanti Connect Secure"] I1["Oct 3 - exploitation begins"] --> I2["Oct 13 - patch released"] --> I3["Oct 13 and Oct 30 - KEV additions"] end subgraph LL["LiteLLM"] L1["May 27 - key leaked"] --> L2["Oct 10 - key used"] --> L3["Oct 21 - malicious release"] --> L4["Oct 23 - maintainers publish the chain"] end
Read the first node of each lane against the third. In every case the defender's clock started well after the attacker's. Dates for the pre-disclosure phases come from incident research and press reporting rather than vendor advisories, so treat them as reported rather than confirmed.
Some widely shared explanations were wrong. The early PHP2Shell write-up pinning the bug on session.upload_progress did not hold up: later analysis calls it one trigger path, not the root cause. Public exploitation claims for the second PHP CVE are also weaker than for the first. If you rewrote an internal advisory based on the first viral explanation, it is worth re-reading now.
For your own write-ups, the pattern worth copying is LiteLLM's: a numbered sequence of what the attacker did with what credential, published even though it was unflattering, and corrected when the first theory turned out wrong.
How this was verified
Facts in this post come from primary sources: the LiteLLM maintainers' posts, the Node.js security release notes, the PHP announcement, GitLab's patch release page, CISA alerts, the KEV catalog and its CSV, Unit 42, and two Microsoft Security Blog posts. The characterisation of the "Black October" label comes from Wikipedia, Halborn and ScruteX.
Still unverified or disputed:
- The age of the PHP bug (about 14 years, "since 2012") and the AI-assisted discovery come from secondary reports, not PHP's advisory.
- The honeypot exploitation detail (shells from two IPs on October 24) is from a single source. CISA's KEV listing on October 26 is the firm confirmation.
- The worst-case severity of the Brotli CVE (code execution) is disputed between Node.js and one independent analyst; exploitation is confirmed only in the sense that CISA lists it in KEV (added October 27), and I have not seen the exploitation evidence itself. GitLab CVE-2026-110264 and Node's other nine CVEs were checked against the KEV catalog on November 12, 2026 and are not listed there.
- Counts of "Black October" incidents differ by outlet, and reporting dates for the eMudhra keys differ.
- Other incidents reported under the label are not covered because I did not cross-check them against primary sources.
- The root-cause accounts in "How each one actually happened" vary in quality, and the table says so per row. The Onigmo mechanism (a signed 16-bit repeat ID) comes from third-party accounts of GitLab's fix commit; I have not read the commit. The BeyondTrust and Ivanti entry paths come from Mandiant's and Volexity's research, not from the vendors. The Fortinet CLI path-traversal description comes from summaries of FG-IR-26-122, not the advisory itself.
- Pre-disclosure exploitation dates (BeyondTrust from August 29, Ivanti from around October 3) are from incident research and press, not vendor advisories.
- The eMudhra account was updated after the first reports: the affected certificate count rose from 8 to 16, and the stated cause moved from "a script generated a second weak key set" to "a script used to move keys between HSMs". Read the latest Mozilla incident report rather than October coverage.
Last verified: November 12, 2026. Details may change; check the linked advisories before acting.
Closing
There will be another month like this one, and the label it gets will matter less than the sorting. The question to practise on each item is: is it exploited, is it a malicious release, or is it a disclosure? The answer decides the work.
Read the causes side by side and one more thing stands out: not one of these was exotic. An unrevoked key, an unverified key ceremony, a decoder that ignored a return value, a counter that did not fit its field, a path argument nobody confined. The next wave will be made of the same material.
What to do about that is the subject of the companion post: the security patch drill, the owners, and the pipeline best practices.
Related reading
Ask AI About the Author
Open this query in ChatGPT, Claude, or Perplexity.
Comments
Comments are open to confirmed email subscribers. Use the email you subscribed with. To edit a comment, delete it and post a new one.
Subscribe to get the new blogs.
Field notes from someone who ships before they write about it. Sovereign AI, AI-SDLC, DevOps, and what 59 production deployments teach you. No spam. Unsubscribe anytime.