In EP5 the vendor you hired to save you was the problem. This week the vendor is not a crook. Its app credential was stolen, and every tenant that trusted it inherited the risk.
Storm-0940, ARTEX, and the ConnectWise Cloud Backup compromise
Sourcing: Microsoft threat intelligence, Huntress incident response, and the ConnectWise advisory. Disclosure: Tom works at Huntress.
The case
- The actor: Microsoft describes Storm-0940 as a China-state-aligned group, active since 2021 and focused on data theft. Its usual playbook is password spraying, then adding credentials to existing OAuth apps for persistence.
- The tool: ARTEX, an open-source agentic AI penetration-testing framework that can drive any AI model from recon through exfiltration. Microsoft says Storm-0940 has used it since at least September 2026 against hundreds of organizations, sometimes reaching privileged cloud access in under three hours.
- The supply chain hit: an app credential for ConnectWise Cloud Backup (formerly SkyKick), an MSP tool with broad read/write access to mail, OneDrive, SharePoint, Teams, and directory data. Huntress notes it was a client assertion credential living in the vendor’s tenant, so nothing a customer did could have caused it. The attribution to Storm-0940 is Microsoft’s assessment.
Timeline (2026, UTC)
| Date | What happened |
|---|---|
| Oct 10 to 14 | Password spray from 144.172.64[.]99: 151,000+ failed logons against 327 accounts at 8 orgs, peaking at 2,900 a minute on Oct 11. No successes. |
| Oct 15, 03:44 to 03:49 | In one tenant, the ConnectWise Cloud Management MS Teams app made itself Global Administrator and planted client secrets (valid to 2028) on two other apps, including Huntress’s own. |
| Oct 15, 06:13 to 08:34 | The Cloud Backup app identity requests Graph tokens tenant after tenant from 144.172.64[.]128, in sorted GUID order, seconds apart. |
| Oct 16 | ConnectWise posts its first advisory; Huntress confirms 162 tenants. |
| Oct 17 | ConnectWise shuts off Cloud Backup and disables seven application identities. |
| Oct 21 | Microsoft publishes the Storm-0940 / ARTEX attribution. |
Receipts
- Microsoft says the actor used ARTEX to attempt sign-ins to more than 2,250 tenants.
- Huntress saw almost 1,000 Entra tenants with sign-in activity from the attacker IP, more than 300 of them successful.
- Post-compromise activity in two tenants took about five minutes and was scripted and indiscriminate. Which apps got backdoored looked random.
- Microsoft also saw downstream Azure tenants where secrets were read at scale from multiple Key Vaults.
- Microsoft stresses this was not a compromise of, or vulnerability in, Microsoft systems.
Hype check
- “Agentic AI” is Microsoft’s characterization. The techniques are classic: spraying, stolen app credentials, self-granted roles, planted secrets. AI changed the speed, not the playbook.
- Huntress has not tied the early Global Admin phase to the same operator. Some vendor-like activity (a kiota-dotnet user agent) may be ConnectWise’s own automation. Unconfirmed.
- “Tokens issued, nothing visible taken” is the honest status. Graph directory reads leave no audit trail.
What MSPs should do
- Disable, don’t delete, the ConnectWise / SkyKick apps. Deleting removes consent and evidence.
- Disabling does not remove planted credentials. Review secrets and certificates on every enterprise app and app registration added since October 13, especially management and security tools.
- Check service principal sign-ins (not the default user sign-ins tab), directory role grants, and Conditional Access exclusions for these apps.
- Longer term: app management policies that restrict client secrets, Conditional Access for workload identities, and fewer Application Administrator holders.
- Your backup vendor going dark is a resilience gap. Do you have a second, isolated copy?
CIS Controls: 15.1, 15.4, and 15.6 (inventory every multi-tenant app with tenant consent, put security requirements in contracts, monitor providers), 5.4 and 6.8 (no vendor app should be able to grant itself Global Administrator), 8.2 and 8.11 (collect and review service principal sign-ins and Entra audit events), 11.4 (isolated recovery data: one backup vendor is a single point of failure).
NIS2 / ENISA (Implementing Regulation 2024/2690 applies directly to MSPs and MSSPs): 5.1 (supplier security requirements), 11.2 and 11.3 (access rights and privileged accounts, including non-human identities), 3.2 (monitoring and logging), 4.2 (backup and redundancy). Under Article 23, an in-scope MSP owes a 24-hour early warning for a significant incident.
The CA private key was the number 4: eMudhra
Sourcing: Mozilla Bugzilla incident record, BleepingComputer, The Hacker News, and the viral X thread that brought it to us.
The case
- Eight eMudhra (emSign) intermediate CAs, six TLS and two code signing, used P-384 private keys that were whole numbers below 256. A real P-384 key is a random 384-bit number. These had about 8 bits of secrecy: anyone with the public certificate could recover the key in at most 255 tries.
- The keys: EM OV TLS CA - G3C was literally 4. Others were 56, 66, 115, 155, 156, 230, and 237.
- Exposure window: generated at an April 30, 2025 key ceremony and reported October 17, 2026, roughly 18 months. eMudhra says most were never used in production and it found no evidence of misuse, but nobody can prove a negative.
- Discovery: a researcher known as Wayne found it scanning public certificate data and proved control of all eight keys by signing the same message with each: “We have a problem here.”
How fast the ecosystem moved (2026)
| Date | Response |
|---|---|
| Oct 17 | Report reaches Mozilla at 20:06 UTC. Firefox blocks via OneCRL about three hours later, no update or restart needed. Chrome blocks the six TLS intermediates the same day. |
| Oct 18 | eMudhra revokes all eight and halts issuance under its G3 root. |
| Oct 20 | Go 1.27.3 / 1.26.10 reject any chain through the eight keys (CVE-2026-111943). Firefox 158.0.1 and ESR updates ship. |
| Oct 22 | Apple adds protections. |
| Ongoing | Mozilla removes trust in emSign ECC Root CA - G3; Google is removing the root from Chrome. eMudhra estimates roughly 30,000 certificates need migration. |
Hype check on the X thread
- The viral theory is that eMudhra read “384-bit” as “pick a number from 1 to 384.” Great line, but the evidence does not fit: every key is below 256 (one byte), not spread up to 384.
- eMudhra told Mozilla a flaw in the ceremony script created a second, weak key pair on the HSM during a key-wrapping test, and those keys were picked for signing because their labels looked like the real ones.
- Mozilla participants point out that a FIPS-validated HSM does not produce a key of 4 on its own. The root cause is still under investigation.
The long tail is your problem
- Browsers fixed themselves in hours. Everything with its own trust store did not: Go binaries must be rebuilt, and BleepingComputer listed Node.js and Bun as pending at publication. macOS’s built-in
/usr/bin/curlmay keep trusting the keys because it does not check revocation. - Containers and appliances with frozen
ca-certificatespackages are the blind spot. - Mozilla’s Dennis Jackson runs a tracker with patched versions and test endpoints.
- If you or a client bought eMudhra/emSign certificates, plan reissuance from another CA now.
CIS Controls: 2.1 and 7.4 (CA bundles, language runtimes, and container base images are software you must inventory and patch), 4.1 (know where apps pin their own trust stores), 15.4 (CAs are providers: require incident notice and migration support).
NIS2 / ENISA: 9.1 (cryptographic policy, key management, and the ability to switch providers), 6.6 (patch management), 5.1 (supply chain security).
Tailworm: turning a zero trust mesh against itself
Sourcing: independent researcher report (Erica Windisch, Cyberdione Labs), The Hacker News, and Tailscale’s public response on r/Tailscale.
The case
- Published October 25: 11 findings against Tailscale 1.104.2 and headscale 0.29.5, tested in a lab October 22 to 24.
- No bulletin, CVE, or fixed version yet at the time of the show. Tailscale’s newest bulletin (TS-2026-013, Oct 21) is an unrelated certificate issue.
- Prerequisites: the attacker already controls one device, and SSH access rules allow port forwarding to the target. This is post-compromise lateral movement, not unauthenticated access from the internet.
Receipts
- Tailscale SSH authorizes by device, not by password or key. One access rule decides whether a device may SSH to a target.
- Root via socket forwarding: standard SSH port forwarding made the root-level tailscaled process connect to a root-only socket. The lab got root and read the password file almost immediately.
- Socket replacement: a second method swapped a root-owned socket for the attacker’s, enabling root command execution against certain services.
- Race condition to rogue node: a time-of-check/time-of-use race captured a device enrollment key and joined the attacker’s machine as a trusted server. This fully worked only where Tailnet Lock was off.
- App connectors: an experimental feature (conn25) let permitted users reach unapproved destinations, including a cloud metadata service.
- On headscale 0.29.5, forwarding cannot be turned off. Treat every SSH grant there as root on the target.
The disclosure fight
- Windisch calls it “reported but not coordinated.” She says she sent the report and proof of concept to Tailscale’s security contact on October 24, a one-day window.
- Tailscale VP of Engineering Mike Shaver confirmed receipt, said the company was already examining the same areas with outside specialists, and is not recommending everyone disable Tailscale SSH.
- No one has independently reproduced the findings. Some researchers question the “wormable” label; others call the root finding serious.
- Tailscale fixed a similar SSH Unix socket forwarding flaw earlier this year in 1.98.9 (TS-2026-004).
Counterpoint: “tailslop”
A community rebuttal repo argues every one of the 11 findings needs a feature you have to switch on, so a default tailscale up install has none of the preconditions. It ships a short, read-only script that checks each finding on a node.
| Finding | Needs this switched on |
|---|---|
| F1 to F3, F5: root via SSH socket forwarding, plus the “worm” | Tailscale SSH and an SSH rule admitting a device |
| F4: app connector (conn25) | Connector configured and advertised |
| F6: headscale unauthenticated DoS / lockout | You run headscale |
F7, F8, F11: serve to sockets, per-mount auth race | An active tailscale serve setup |
| F9: Funnel exposure | Funnel on |
| F10: off-tunnel serve with no ACLs | TS_SERVE_ALLOW_ALL_INTERFACES set |
- Fair point: opt-in matters. Most consumer and homelab installs are not exposed.
- But opt-in is not rare in business. Tailscale SSH and broad SSH grants are exactly what MSPs and DevOps teams turn on, so each red line in that script is also your audit list.
- Two claims to push back on: tailslop says there is no vendor acknowledgement, but Tailscale’s VP of Engineering publicly confirmed receipt. It also says the bug class was fixed in 1.98.9, yet Tailworm tested the newer 1.104.2.
- Neither side is independently verified. tailslop is a one-commit repo from an unaffiliated author: a useful checklist, not a verdict. Read the script before you run it.
What to do
- Zero trust is not a product, it is policy granularity. Broad identity or tag grants turn one foothold into fleet-wide blast radius. Per-pair source-to-destination rules were the one control that stopped spread in the lab.
- Turn off SSH port forwarding per rule. Remove unneeded app connector permissions and
tailscale serveforwards to Unix sockets. - Enable Tailnet Lock, node key expiry, SSH check mode, and auto-updates. Check mode adds a barrier but does not fix the escalation.
- When a device is compromised, delete it at the control plane. Reimaging does not revoke copied keys.
CIS Controls: 6.8 (role-based access: per-pair grants instead of broad tags), 4.8 (disable SSH forwarding and app connectors you do not use), 12.2 and 13.4 (secure network architecture and filtering between segments), 7.2 and 7.7 (track an unpatched, no-CVE issue until a fix ships).
NIS2 / ENISA: 6.10 (vulnerability handling and disclosure: the disclosure debate itself), 6.8 (network segmentation), 11.2 (management of access rights).
PHP2Shell: leaked before the patch
Sourcing: PHP release notes and GitHub advisory, watchTowr’s confirmation, and The Hacker News.
The case
- Two pre-auth RCEs in the PHP core, each CVSS v4 9.2: CVE-2026-109618 (code execution via out-of-memory corruption) and CVE-2026-109619 (code execution via stale global state).
- Leaked first. Details surfaced October 20, ahead of coordinated disclosure. watchTowr was first to publicly confirm the bugs were real.
- Emergency release October 21 at 14:00 UTC: 8.5.12, 8.4.27, 8.3.36, and 8.2.35. PHP says there are no complete mitigations; updating is the only safe choice.
- 8.1 and older get no fix, and PHP 8.2 reaches end of life December 31, 2026.
Receipts
- Amazon’s honeypots logged an exploit attempt on October 17, four days before disclosure.
- Cloudflare saw attempts climb from tens of thousands within 45 minutes of disclosure to millions by early October 22.
- Sophos and Arctic Wolf saw attempts to drop a Mirai variant. As of the show, no confirmed code execution in the wild, and researchers said a reliable exploit was harder to build than expected.
- Then a third one: on October 23 PHP flagged CVE-2026-115560, which needs an unusual session serializer setup. It is being fixed in the next routine release.
Enterprise blast radius
PHP ships inside firewalls, NAS boxes, SIEMs, phone systems, and OT gear. VulnCheck’s Patrick Garrity posted a sample of affected enterprise products, mapped from vendor advisories to CPEs in VulnCheck NVD++. He says it is a partial list.
| Category | Products VulnCheck lists as affected |
|---|---|
| Firewall / gateway | Palo Alto PAN-OS, Panorama; OPNsense; Check Point QSG, Quantum Spark, CloudGuard |
| Load balancer / WAF | F5 BIG-IP (21 modules) |
| NAS / storage | QNAP QTS, QuMagie, Notes Station 3; Synology Calendar, Mail Station |
| Security / SIEM / endpoint | Tenable Security Center; IBM QRadar; Quest KACE SMA and firmware; HP Device Manager |
| Identity / access | Okta Access Gateway; Aruba ClearPass |
| Monitoring / API | Progress Flowmon; IBM SevOne, API Connect |
| Hosting / file sharing | Plesk, Plesk Obsidian; FileCloud |
| Unified comms / telecom | Cisco Expressway; Mitel CMG Suite, MiContact Center; Atos OpenScape Branch, SBC; Unify OpenScape Voice Trace |
| Industrial / OT | B&R APROL; Siemens RUGGEDCOM APE1808 |
Inclusion reflects VulnCheck’s mapping, not confirmed exploitability. Check each vendor’s own advisory. You cannot patch the PHP inside an appliance yourself, so every one of these waits on vendor firmware.
The stealmybitcoin.com challenge, and the solve
- An anonymous Hacker News user put a bitcoin key on a server running unpatched PHP 8.4.26, readable through a
print-flagbinary. First to run it from outside keeps the bitcoin. It opened October 24 at about 20:30 UTC with roughly $500; donations pushed it past $2,000. - For about the first 10 hours, nginx sent requests to a static HTML file through PHP’s single-threaded dev server, a path that never reached the vulnerable multipart parser. Skeptics cited the unclaimed wallet as proof the bugs were not exploitable. Once the site moved to a real PHP page, they were.
- Won October 25 at 15:47 UTC, 19.28 hours after launch, by KillaBoi, for 0.02511679 BTC (about $2,021). Per the write-up, in at most 20 HTTP requests:
- A small multipart upload with session upload-progress fields pushed PHP past its 128 MiB memory limit mid-parse, leaving stale state in a reused worker.
- Follow-up requests leaked memory back through the
PHPSESSIDcookie, first a heap address and then a code address, defeating address randomization. - A final request planted a forged internal structure that PHP’s cleanup code called as
system(), which ranprint-flag.
- Brittle, not magic: it only works on the exact build it was calibrated for (Alpine PHP 8.4.26, built-in server, four workers). A Debian build with the same version fails. It succeeded about 7 of 10 times in the author’s lab.
- Honest gaps: the author says the original live request was not fully captured, and the recovered key did not derive the advertised prize address. The creator acknowledged that was a setup mistake on their side.
Takeaways: “Nobody has claimed it” was never evidence of safety; the deployment just did not reach the bug. Configuration is attack surface in both directions, but a good nginx setup is not a patch. Exploitation is hard but proven, and a public PoC now exists.
What to do
- Interim hardening, not a fix:
session.upload_progress.enabled = 0blocks one path for CVE-2026-109619 and covers CVE-2026-115560. On PHP 8.5,fatal_error_backtraces = Offblocks the confirmed backtrace path. A server-level memory limit only narrows CVE-2026-109618. - For most WordPress and shared hosting clients the patch sits with the host. Ask hosts for their patch status in writing.
- Be wary of “PoC” repos that appear during a leak. Read before you run, and never on a production box.
CIS Controls: 2.1 and 2.2 (software inventory, and supported software: PHP 8.1 and earlier now, 8.2 after December 31), 7.4 and 7.7 (automated application patching, remediate detected vulnerabilities), 4.1 (php.ini hardening as a documented baseline), 15.4 (firmware patch timelines in vendor contracts).
NIS2 / ENISA: 6.6 and 6.10 (patch management, vulnerability handling), 6.3 (configuration management), 5.1 and 6.1 (supply chain, and security in acquisition, such as requiring SBOMs).
Node2Shell: the bug was in Brotli, not Node
Sourcing: the Node.js October 2026 security releases, Imperva’s proof of concept, and The Hacker News.
The case
- October 21: Node.js fixed 10 CVEs across every supported line: 22.23.4, 24.22.1, and 26.12.1.
- The headline: CVE-2026-111497, an out-of-bounds write in the bundled Brotli decoder that Node.js says permits remote code execution. Node.js rates it High; some outlets cite 9.2. The bug is upstream in Google’s Brotli, which shipped its own fixes the same day.
- Also fixed: TLS certificate hostname bypasses (CVE-2026-105483 with fullwidth digits, CVE-2026-106069) and a
dns.resolveNUL-truncation bug (CVE-2026-105482). Those matter for SSRF defenses and webhooks. - Node.js 20 and older are end of life (20.x ended April 30, 2026) and get no fix.
Receipts
- Imperva ran code on the official Node.js 24.22.0 image for Linux arm64, with no debugger or custom build. It took several attempts, and other architectures were not tested.
- Two ways in: a Brotli response read through built-in
fetch(), or a Brotli request body decoded by Express 5 body parsers (express.json()and friends now decode Brotli). - On 24.22.1 the same data was rejected. No in-the-wild exploitation reported as of October 22.
- The same Brotli flaw also hits Bun, Python, and other software that bundles the decoder.
What to do
- Upgrading
nextorexpressdoes not patch the Node binary underneath. The runtime is a separate patch. - Container images and appliances that bundle Node are the blind spot. Package inventories often miss them.
- There is no workaround inside Node.js. WAF rules block inbound attacks but not Brotli responses your app fetches.
CIS Controls: 2.1 and 2.2 (find every Node binary, including inside containers), 16.4 and 16.5 (track bundled third-party components like Brotli and keep them current), 7.4 (automated application patching).
NIS2 / ENISA: 6.2 (secure development life cycle), 6.6 (patch management), 12.4 (asset inventory).
Three things to do before Monday
- Audit every vendor app in your tenants (CIS 5.4, 15.4; NIS2 5.1, 11.3). Disable, don’t delete, the ConnectWise / SkyKick apps. Review secrets and certificates on all app registrations added since October 13, and remove any directory role you did not grant.
- Patch the runtimes, not just the apps (CIS 2.2, 7.4; NIS2 6.6). PHP 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 and Node.js 22.23.4 / 24.22.1 / 26.12.1, including containers and hosting providers. Update CA bundles and rebuild Go apps to drop the eMudhra keys. Retire PHP 8.1 and Node 20.
- Tighten your overlay network policy (CIS 4.8, 6.8; NIS2 6.8, 11.2). Per-pair Tailscale SSH rules, forwarding off, Tailnet Lock and node key expiry on, and watch for Tailscale’s bulletin.
Sources
Storm-0940 / ConnectWise
- Microsoft: Storm-0940 uses ARTEX in ConnectWise supply chain compromise
- Huntress: ConnectWise (SkyKick) vendor credentials abused in M365 attacks
- ConnectWise Trust Center: Cloud Backup advisories
- BleepingComputer: Hackers breach M365 tenants via ConnectWise supply chain attack
eMudhra
- Mozilla Bugzilla 2083449: eMudhra intermediate key compromise
- BleepingComputer: Mozilla, Google, Apple block compromised eMudhra CA certificates
- The Hacker News: Go emergency update blocking eight CA keys
- Dennis Jackson: eMudhra incident tracker
- @IzzatStatus on X
Tailworm
- Tailworm report, Cyberdione Labs
- The Hacker News: Unpatched Tailscale SSH flaws
- Tailscale on r/Tailscale: Recent vulnerability reports
- Tailscale security bulletins
- Tailscale TS-2026-004
- Brandefense: Tailworm status tracker
- orlyjamie/tailslop: Tailworm triage rebuttal
PHP2Shell
- PHP 8.4.27 release
- PHP 8.2.35 release
- PHP security advisory GHSA-6wmf-4rv5-p3rp
- watchTowr: PHP2Shell FAQ
- The Hacker News: PHP warns of another unpatched RCE risk
- VulnCheck (Patrick Garrity): PHP2Shell enterprise products affected, LinkedIn post, October 26
- stealmybitcoin.com and terms
- KillaBoi: StealMyBitcoin-PoC write-up
- Cybersecurity News: Hacker exploits PHP2Shell to win $2,000 bitcoin challenge
- Pasquale Pillitteri: StealMyBitcoin hacked in 19 hours
Node2Shell