Actively exploited CVEs and flaws, November 2026: 10 to fix
Ten exposures attackers are already using: CVEs, a supply-chain compromise with no CVE, and misconfigurations, each with the check and the fix.
This issue is about the gap between a patched system and an unexposed one: ten flaws added to CISA's exploited list between 10 and 30 October that are worth acting on, and one supply-chain compromise that never got a CVE number at all. The first entry is why that gap matters.
Between 10 and 30 October, 27 flaws went onto the CISA list of things attackers are already using. Ten of them are worth acting on in this issue, and one of those is not a CVE at all. If you only have an hour, start with the three at the top: they end in code execution without requiring a login.
1. Ivanti Connect Secure, and what the chain actually looked like
On 3 October, someone began using an Ivanti Connect Secure appliance at a network monitoring customer as a stepping stone. It was fully patched for the time, build 22.8R2.4 (build 19097). The operator, tracked by Volexity as UTA0576, chained three separate flaws to get from an unauthenticated HTTP request to root, then spent days pulling credentials out of the customer's Active Directory.
There was no backdoor and no web shell. Every command the operator ran re-exploited the appliance, and the output came back inside the HTTP response. The debug log and Linux audit log were edited afterwards to remove the relevant window, which is why the published analysis is based on memory images and core dumps rather than logs. Volexity's investigation started on 5 October and the write-up landed on 13 October.
The authentication bypass
The entry point is /dana-na/auth/url_default/welcome.cgi, the script that serves the login page and is therefore reachable without credentials. The request also carried X-DSCGI-PATH: /home/webserver/htdocs/dana/fb/smb/wu.cgi. The appliance used the URL to decide whether the request was allowed and the header to decide where to send it, so a public URL delivered traffic to an internal CGI script.
The upload race
wu.cgi is an upload handler, and its checks are in the wrong order. It hashes the filename the client supplied, writes the body to /home/runtime/tmp/<MD5 of filename>, and only afterwards tests whether the file is a valid ZIP. A Perl script sent with a .zip name fails that test and gets deleted, but it exists on disk long enough to be executed. The operator fired parallel requests carrying X-DSCGI-PATH: /home/runtime/tmp/<MD5 of filename> and won the race between execution and deletion.
What ran was a chain: the Perl script started a Bash script, which started a Python script delivered Base64-encoded and zlib-compressed, decompressed and handed to exec(). The Python payload never existed as a file, only in memory, which is the first reason this was hard to find afterwards.
The privilege escalation
Code execution landed as the cgi-server user, not root. The appliance runs a privileged service called dsinvoked that performs maintenance tasks as root on demand, and it looks up which program each task runs in DSCache, the shared configuration store.
The exploit patched the running process's in-memory copy of /home/lib/libdsplibs.so so it could write to DSCache, repointed an existing maintenance task at the Perl interpreter instead of its legitimate script, and asked dsinvoked to run it with a malicious Perl script as the argument. Root, confirmed by checking whether /etc/shadow was readable. Then it put everything back: the DSCache entry restored to /home/bin/updateOpswatSDK.pl, the library restored, the patched instruction byte in process memory rewritten through /proc/self/mem. The copy on disk was never touched.
That is why Ivanti's Integrity Checker Tool reported nothing. It looks for unexpected file modifications, and there were none.
What the operator took
The appliance holds a domain service account, and that is what made the rest possible. Volexity recovered the tooling from memory:
/tmp/ml.pyand/tmp/rq5.py: a custom LDAPv3 client that authenticated to an internal domain controller as the appliance's account and queried for LAPS local administrator passwords, BitLocker recovery keys,userPasswordandunixUserPasswordattributes, and logon script paths. Results were written as zlib-compressed Base64 JSON in/tmp/and exfiltrated through the exploit channel./data/.icscap/h.pywith a renamedtcpdumprunning asdsstatmond: eight rotating capture files under/data/.icscap/, filtered to plaintext ports, parsed for LDAP credentials, HTTP Basic credentials and NTLM challenge-response hashes./tmp/mk.pyand/tmp/rr.py: a Python Kerberos implementation used to test credentials, carrying Kerberoast capability that the operator did not end up using.sp_run.py, with output insp_out.txtandspray_hits.json: password spraying against Active Directory accounts, after/etc/resolv.confwas read and internal domains resolved.- Configuration and authentication data from
/home/etc/pulse/,/home/etc/,/home/*.cfgand/home/runtime, plus usernames mined fromlog.events.vc0.
Cleanup went with it: entries removed from /home/runtime/dlogs/debuglog and /var/log/audit/audit.log by reading, filtering and rewriting the files in place so older entries stayed; the Perl payload unlinking its own /home/runtime/tmp/ics-root-run-inband-*.pl; result files and helper scripts deleted; cleanup processes started with stdin, stdout and stderr pointed at /dev/null. Memory analysis caught the operator anyway. Volexity's first two alerts pointed at dsstatmond, PID 5012, sniffing traffic through a BPF filter from a hidden directory.
What to look for on your own appliance
The presence of that sniffer and those capture files is the most durable evidence, because they were written to disk:
ls -la /data/.icscap/ 2>/dev/null
ps -eo pid,user,args | grep -iE 'dsstatmond|tcpdump' | grep -v grep
# leftover staging from the exploit chain
ls -la /home/runtime/tmp/ 2>/dev/null | grep -E 'ics-root-(run|result)-inband'
ls -la /tmp/ml.py /tmp/rq5.py /tmp/mk.py /tmp/rr.py /tmp/pu.txt 2>/dev/null
# log gaps: the payload rewrites these in place, so look for a hole, not a deletion
ls -l --time-style=full-iso /home/runtime/dlogs/debuglog /var/log/audit/audit.log 2>/dev/null
grep -aiE 'X-DSCGI-PATH' /var/log/httproot/access.log 2>/dev/null | tail -50An empty result is weak evidence of safety here. The library patch lived in memory, the configuration store was restored, and the logs were rewritten rather than removed, so the appliance can look clean and still have been rooted. If any of the file paths above exist, treat the domain service account as compromised and the estate as breached, not as patched.
The fix
Ivanti patched the authentication bypass and RCE on 13 October under CVE-2026-104935, and the privilege escalation on 29 October as CVE-2026-111357, in 22.8R2.5 or later. These ship as full appliance images, so book the window and take the config backup first. If the window is weeks out, take the appliance off direct internet exposure; an appliance sitting behind a VPN is not a thing an unauthenticated request can reach.
The second Ivanti entry, CVE-2026-118527, is the quieter one: predictable filenames let an authenticated attacker write files to a known location. Fixed in 25.1.1.3 or 22.8R2.6. Both are in KEV, with federal deadlines of 2 and 13 November.
2. GitLab, where the patched build is still vulnerable
Two flaws, both 10 out of 10, both running code for someone with no account. CVE-2026-97229 needs a crafted regular expression to reach a compiler, which means a path where an unauthenticated visitor can push something into a pipeline. CVE-2026-110264 is an integer overflow while compiling a regex. Same door, different lock.
They were fixed four days apart in different version sets. 97229 is fixed by 19.2.8, 19.3.5 or 19.4.2. 110264 needs 19.2.9, 19.3.6, 19.4.3, 19.5.1, or 18.11.13 on the 18 line. A box on 19.2.8 is patched for the first and open to the second, and that gap is where organisations have been sitting all month.
Then there is the part that is easy to miss in the upgrade notes: the 110264 fix is a patch to Ruby, not to GitLab code. It only travels inside the official packages and images, so a self-compiled install on its own Ruby stays vulnerable no matter which GitLab version it claims. GitLab's own release notes say it plainly: Ruby 3.3.13, 3.4.12 or 4.0.9 and later, or the upgrade does nothing for that flaw. The Ruby fix itself is documented here.
curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
https://gitlab.example.com/api/v4/version
ruby -v # only relevant if you do not use the official packagesDo not test the exploit against production. Version comparison is the test; probing is the incident. If you cannot patch immediately, removing anonymous access to public projects closes the 110264 entry point without fixing anything.
3. PHP, where nobody knows the version
Both CVE-2026-109618 and CVE-2026-109619 give an outsider code execution with no credentials, and it happens before your application code runs. The first is memory left in a bad state after an out-of-memory jump; the second is global state still pointing at a request that has already been freed.
Reaching either one means making a request exhaust memory while staying inside its own limits. The PHP advisory lists three ways in: a multipart request without a usable declared length, one part with an unlimited number of headers, and deeply nested field names that multiply array work. Then the SAPI decides how bad it is. Apache with mod_php runs the request shutdown path even when startup failed, which is the worst case. PHP-FPM kills the child when startup fails, which blocks that route but not every route.
Fixed in 8.2.35, 8.3.36, 8.4.27 and 8.5.12. The advisory is blunt that updating is the only complete mitigation, so there is no configuration to hide behind.
Finding every interpreter is the actual work, because the vulnerable one is usually inside an image your team did not build:
docker ps -q | xargs -r -I{} docker exec {} php -r 'echo PHP_VERSION,"\n";' 2>/dev/null | sort -u4. Brotli, the one you did not install on purpose
CVE-2026-111497 is a buffer overflow in the Brotli decoder, reachable by anyone who can send you a compressed body. Versions 1.0.3 through 1.2.0 are affected on every platform, and the outcome ranges from reading adjacent memory to running code.
Almost nobody installs Brotli deliberately. It arrives with Node.js, Bun, Python's brotli and brotlicffi packages, and Envoy, which is why the useful question is not whether you use it but which of your runtimes carry a vulnerable decoder. Node.js fixed it on 21 October across the 22.x, 24.x and 26.x lines. The Go port shipped 1.2.7.
python3 -c "import brotli; print(brotli.__version__)" 2>/dev/null
node -p "process.versions.brotli + ' (node ' + process.version + ')'"
npm ls brotli --all 2>/dev/null | head -40Patch the process that decompresses untrusted bodies first. A proxy that only forwards bytes is not the emergency. You will see different "fixed versions" quoted for this one depending on who is writing; all of them are true inside their own ecosystem, which is why it keeps getting reported inconsistently.
5. Collabora's CODE server inside Nextcloud
CVE-2026-110447 is command injection in proxy.php, and it fires when the CODE server is not running, for example just after a restart. It was exploited in the wild in September and October, and the upstream issue is worth reading for the conditions.
The scope is narrower than the coverage suggested. This is the Nextcloud richdocumentscode app before 26.4.303. If you run Collabora Online in its own container rather than as the Nextcloud app, it is not your bug. Patch to 26.4.303, or remove the app, which is a genuine fix here because the vulnerable CODE server is what the app ships.
6. The OVHcloud CLI, where the binaries changed under you
On 19 October, a compromised OVHcloud developer account replaced the published release archives of ovh/ovhcloud-cli with a credential stealer. Versions v0.11.0 through v0.15.0, for about 94 minutes between 12:47 and 14:21 UTC. Source, tags and the build pipeline were untouched. Only the artifacts attached to releases changed, and for the later versions the checksum file was replaced too, so checking the download against it proved nothing.
There is no CVE. Coverage focused on the stolen account; the part that matters operationally is that anyone who installed in that window has a stealer's worth of credentials on disk. OVHcloud's advice is to change every secret on the machine, which is a bigger job than it sounds and the correct one.
ovhcloud version 2>/dev/null || command -v ovhcloud
ls -l --time-style=full-iso "$(command -v ovhcloud)" 2>/dev/nullRebuild on v0.16.0, then rotate cloud keys, SSH keys, registry tokens and anything else a stealer would find useful.
7. Release immutability, the setting that allowed item 6
OVHcloud's own post-mortem names the cause: the repository was not configured to make releases immutable, so anyone holding the right permissions could overwrite an artifact that had already been published and downloaded.
That makes "I got it from the official releases page" a weaker statement than it feels. It is evidence the page said something at a particular time, not that the binary you are running is the one that was built.
gh release view v0.16.0 --repo ovh/ovhcloud-cli --json isImmutable,tagName,assets
sha256sum ./ovhcloud && grep ovhcloud ./checksums.txtTurn immutability on for repositories you own. For the ones you consume, pin images by digest and verify signatures where they exist; SLSA's requirements describe what "verified" is meant to mean, and GitHub's docs cover the setting. Nothing here shows up in a scanner. The outcome is a stolen key that looks like normal API traffic.
8. .env, .git and stray backups in the web root
The oldest finding in the book, and still the one that pays. A readable .env hands over database and API credentials. A readable .git/ hands over the entire history, including the secret someone deleted in a later commit. A backup.sql in the document root hands over everything at once.
Before scanning for any of it, check whether the site answers 200 to every path. On a single-page app it will, and then a path scan reports one finding ten times while you chase nothing.
curl -s -o /dev/null -w '%{http_code} %{size_download}\n' https://app.example.com/definitely-not-a-real-path-9f3a2b
for p in .env .git/config .git/HEAD backup.sql www.zip .DS_Store; do
printf '%-14s ' "$p"
curl -s -o /dev/null -w '%{http_code} %{size_download}\n' "https://app.example.com/$p"
doneRead the body, not the status. A 200 that returns the app shell means nothing; a 200 that returns key-value pairs is a breach. Stop once you have confirmed the value, because enumerating further on a system you do not own is the part that gets people into trouble. The OWASP testing guide covers the deployment cases and the backup-file chapter is worth ten minutes if this is your first pass at it.
Serve only from the directory you mean to expose, block dotfiles at the web server, rotate whatever was reachable, then delete it. Rotating without deleting puts you back here next week.
9. Plex Media Server, and why "unauthenticated" was wrong
CVE-2026-96656 lets an admin user write arbitrary files that execute on load. The TranscoderH264Options preference is appended verbatim to the x264 option string, and at startup the server runs .so files without checking signatures, the execute bit or symbols. The release notes carry the fix.
One correction to how this was reported: 96656 needs an admin account, not an anonymous visitor. "Unauthenticated" was applied to the whole group of Plex CVEs and that is wrong for this one. On a media server, admin is often whoever set it up two years ago, which is not much comfort but is a different risk from a drive-by. The others in the set, CVE-2026-96652 among them, are SSRF and encoded-URI problems.
Fixed in 1.43.3.10861. If the server is exposed to the internet, take it off while you patch.
10. VMware ESX, the flaw you will never prioritise
CVE-2026-41709 lets an administrator perform operations that are never logged. It scores 2.7, and that score is exactly why it will sit in a backlog until the estate is retired.
What an intruder gets from it is the removal of evidence rather than access, which makes it a detection problem before it is a patching one. The Broadcom advisory has the build numbers. More useful: check whether host-level event forwarding to your SIEM actually works. That gap is exploitable whether or not this patch lands.
The rest of the window
The other 17 are KEV-listed and worth patching, but they are version comparisons without a precondition interesting enough to write up.
- Network edge: Cisco Secure Email Gateway (CVE-2026-76519), Cisco Secure Firewall ASA and FTD (CVE-2026-76418, a device reload when secondary authentication is configured), PAN-OS (CVE-2026-0322), FortiOS and FortiProxy (CVE-2025-61624), Arista VeloCloud (CVE-2026-114625, an authenticated user climbing to operator).
- Web and collaboration: Adobe Commerce (CVE-2026-48356, needs user interaction), Atlassian Data Center (CVE-2026-21589), SiteGuard (CVE-2026-106931), Siemens Software Center (CVE-2026-110936).
- Remote access: BeyondTrust Remote Support (CVE-2026-102764), AhsayCBS (CVE-2026-105133 and -105134).
- Endpoints: Windows Shell (CVE-2026-96951), the Linux kernel (CVE-2026-46300).
The KEV feed carries each deadline, and several have already passed.
What I checked, and what I did not
Version ranges, scores and preconditions come from the NVD records, vendor advisories and the write-ups linked above, read on 4 November 2026, with the KEV catalogue at 1,767 entries. Where sources disagree, as they do on the Brotli fix, I have said so instead of picking one quietly.
None of this was tested against a system I do not own, and no host named here is a live target. Every check above is a version read or a log search on machines you control. If you are in the middle of one of these right now, start with the first 24 hours after a breach; earlier briefs are under notable security news. New issues are listed on the Security Round-up.