
Your asset inventory says Node.js is current everywhere. The October security release went out through the pipeline without drama. The scanner is green.
Now open CISA's Known Exploited Vulnerabilities catalog and look up the bug you just patched. The entry does not mention Node.js. It is filed under vendor Google, product Brotli, as the "Google Brotli Unchecked Return Value Vulnerability."
If your patch list is built by matching advisories to the names of products you run, you may have just missed this one on every host where it still matters — and fixed it on some where it was never the problem. That is what happens when a vulnerability lives in a library and the industry names it after one of its consumers. Red Hat's own bulletin carries the popular nickname in its title, in quotation marks, beside the accurate description: "Out-of-Bounds Write - Google Brotli Decoder (CVE-2026-111497)."
CVE-2026-111497 is an out-of-bounds write in the Google Brotli decompression library, reachable by any application that decompresses attacker-supplied Brotli data.
Red Hat locates it precisely: "An out-of-bounds write in the block-type switch handling in `c/dec/decode.c` can be triggered by a crafted Brotli-compressed stream." The Node.js project describes the same defect from its own side — "an invalid block switch was reported as a temporary need for more input instead of a permanent format error, so the streaming decoder kept appending input bytes to an eight-byte internal buffer."
So the mechanism is a misclassified error, not a parsing mistake: the decoder reported a permanently malformed stream as one that merely had not finished arriving, and the caller kept feeding it. CISA files it under CWE-252, unchecked return value, with CWE-787, out-of-bounds write — the mechanism in two identifiers.
Upstream Brotli shipped fixes in v1.2.1, v1.1.1 and v1.0.10, all released on 21 October 2026, each carrying the same release note: "CVE-2026-111497: out-of-bounds write permits remote code execution." Debian and Ubuntu both give the remediation in one sentence: "Users need to update any Brotli libraries or binaries between 1.0.3 through 1.2.0 to the latest available version: 1.0.10 or 1.1.1 or 1.2.1." The defect was introduced in the commit that became 1.0.3.
Node.js published its advisory the same day, stating the flaw "affects Node.js 26.x, 24.x, and 22.x," with releases "available on, or shortly after, Wednesday, October 21, 2026" — v22.23.4, v24.22.1 and v26.12.1. Two honest caveats: the post does not map this CVE to a specific one of those three versions, and it does not name 20.x either way, saying only that "End-of-Life versions are always affected when a security release occurs."
CISA added the CVE to its catalog on 27 October 2026, with a federal remediation due date of 10 November 2026.
Because it is a Brotli bug. Node.js is one of the things that ships it.
This matters operationally, not pedantically. The popular name attaches the issue to a runtime; the authoritative catalog entry attaches it to a compression library. Those two framings produce different patch lists, and the library framing is the correct one, because Brotli is a general-purpose decoder that software across several languages links or vendors.
The consequence: an exposure review that enumerates your runtimes will not find every instance. One that enumerates your copies of the Brotli decoder will. This is the ordinary shape of software supply chain risk — the component you are exposed through is frequently not one you chose, or named, or know you have.
Sometimes. Sometimes it does nothing, and sometimes you did not need to.
It depends on whether your build links the system Brotli library or carries its own bundled copy, and that varies by distribution, by release, and by major version:
Read those together and the conclusion is uncomfortable but useful: `node -v` does not answer the question. On a host running a distribution-built Node.js that links the system library, the Node.js version is close to irrelevant and the Brotli package version is the whole answer. On a host running an upstream Node.js tarball, or a container image built from one, the reverse is true. The split runs per distribution, per release and per major version, which is precisely the point — there is no rule you can carry from one host to the next.
A version number is not evidence of anything until you know what it is a version of. This is the same failure mode as a check-the-box penetration test: the artifact looks like proof and is not.

Six checks, in the order that resolves exposure fastest. The first eliminates the most hosts.

1. Does the application decompress Brotli it did not produce? This is the precondition, and it is narrower than "do you use Brotli." Red Hat states that "exploitation requires that the target decompress attacker-controlled Brotli data (for example HTTP content negotiated with `Content-Encoding: br`, or APIs such as Node.js zlib / `fetch()` that decode Brotli)." Microsoft says the same of .NET: applications may be affected if they "process Brotli-compressed data through ASP.NET Core request decompression, HttpClient automatic response decompression, or the System.IO.Compression Brotli APIs" — and adds that "request decompression and automatic response decompression are not enabled by default." Compressing a response does not exercise the decoder.
Red Hat's bulletin draws the circle wider than the mechanism strictly requires, though: it lists "HTTP servers or clients that negotiate `Content-Encoding: br` with untrusted peers" among common exposure scenarios, and advises configuring a reverse proxy to "strip or reject `Content-Encoding: br` on requests and responses from untrusted clients." Treat negotiation, not only decoding, as the trigger for a closer look.
Our inference, not a sourced claim: the same shape covers anything that fetches a URL someone else supplied — webhook deliveries, link preview generators, document and image fetchers, feed readers — because each decompresses a response it did not produce.
2. Is your runtime linked against the system library, or carrying its own? On Linux this is one command: `ldd "$(command -v node)" | grep -i brotli`. Output naming a shared object means the system package version is the answer that matters; empty output means the runtime carries its own copy and the runtime version is the answer. Run it per build, not per fleet — the same application image can answer differently on two base images.
3. Enumerate the other consumers on the host, not just the runtime you were told about. The primary sources name far more than Node.js. Red Hat's bulletin lists Firefox and Thunderbird, which "embed their own copy for browser-side HTTP decompression"; the `python-brotli`, `python3-brotli` and `python3.12-brotli` bindings; and `jbcs-httpd24-brotli` in JBoss Core Services — and lists RHEL 7, 8, 9 and 10 as directly affected. Debian adds `python-brotlicffi`. Microsoft shipped separate out-of-band .NET updates on 25 October covering .NET 8 (8.0.33), .NET 9 (9.0.22), .NET 10 (10.0.14) and .NET 11 Release Candidate 3, while Red Hat notes .NET 8.0 bundles Brotli on RHEL 8, 9 and 10 where .NET 9.0, 10.0 and 11.0 use the system copy. Ubuntu lists `dotnet6` on 22.04 as "Vulnerable, fix deferred" and `dotnet7` as ignored, being end-of-life upstream.
If you take one thing from that list, take the browsers. On most corporate estates they are the largest population of Brotli decoders by a wide margin, and they appear in no inventory built from server runtimes. To find the rest, ask the package database rather than the asset register: `rpm -qa | grep -i brotli` or `dpkg -l | grep -i brotli`.

4. Restart what you patched. Updating a shared library does not change what an already-running process has mapped. A long-lived API server, worker pool or proxy keeps using the old decoder until it restarts. To find the processes still holding the old copy: `grep -l brotli /proc/*/maps` and compare against the patch time, or `lsof +L1 | grep -i brotli` for deleted-but-mapped files. This is the step that gets skipped, and it is why a host can be fully patched on disk and fully exposed in memory.
5. Check the image, not the host. For containerized workloads the relevant Brotli is the one in the image. Rebuilding against an unpatched base layer produces a fresh image that is still vulnerable, and the registry's scan label will not reliably tell you. Query the image's own package database in a throwaway container instead.
6. Trust your distribution's tracker over the upstream changelog. Brotli's own `CHANGELOG.md` does not mention this CVE at all — its newest entry is 1.2.0, dated October 2025, and the only CVE in the file is one from 2020. The release notes on the tagged releases carry it; the changelog does not. The authoritative statement about your exposure is the security tracker entry for your distribution and release. Even there, verify on the host: Debian's page currently reports two slightly different fixed versions for `nodejs` in unstable in two different tables.
Because the scoring bodies disagree about how hard this is to exploit, and that single dimension moves the score by nearly two points.
Red Hat rates the issue Important, with a CVSS v3.1 base score of 8.1 and the vector `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H`. NVD's score, as Red Hat's own page records it, is 9.8, with an identical vector except `AC:L`. Ubuntu carries the 9.8 v3.1 figure and a CVSS 4.0 base of 9.2. The Node.js advisory assigns no numeric score at all and calls it "high."
Compare the two v3.1 vectors metric by metric and every value matches except one: Attack Complexity. The entire gap between 8.1 and 9.8 is a disagreement about whether turning this memory corruption into reliable code execution is routine or difficult. Red Hat argues difficult, and publishes its reasoning — "the need for a crafted malformed Brotli stream to hit the invalid block-switch path, plus Red Hat platform hardenings (ASLR/NX/FORTIFY/SELinux) that raise the bar for reliable RCE" — while stating plainly that those hardenings "do not eliminate crashes or all impact."

Treat those scores as what they are: different bodies' opinions about a property none of them can settle for your environment. The honest reading is that reliable code execution is hard and memory disclosure and process crashes are not. Note also what the KEV entry does not do: it assigns no severity, because the catalog has no severity field. A catalog of exploited vulnerabilities is an exploitation claim, not a rating — conflating the two is how an "Important" or "High" label comes to look like a contradiction of CISA.
If you are triaging today, triage on the precondition in check 1 and the linkage in check 2. Those two answers change your real risk far more than choosing between 8.1 and 9.8 does.
Less than you would like, and it is better to know that in advance.
No primary source we could read publishes an indicator set for this CVE. There is no signature to grep for, because the malicious input is a compressed stream malformed in a way that a legitimately truncated stream also resembles, arriving on a code path that exists to accept arbitrary compressed bytes. Debian's tracker links a Project Zero issue for this bug that was not publicly readable at the time of writing; if a reproducer appears there it changes the detection picture, not the exposure picture.
One caution on reading the KEV record itself. Its `forensicTriage` field is set to `No` for this CVE, and that is sometimes taken as a statement that there is nothing to find. It is not. CISA's own schema defines the field as whether forensic triage is required under its binding operational directive — an obligation flag, not an assessment of detectability.
So a failed attempt most likely looks like a crash in your logs, or like nothing at all. A successful one looks like whatever the attacker did next. If you want to know whether you were targeted between 21 October and the day you patched, the honest answer is that you probably cannot tell from telemetry you already have — and anyone who says otherwise should be asked which artifact they are matching on.
That leaves posture rather than detection as the useful question, which is why the six checks are worth more here than a hunt. Build the inventory of Brotli copies, confirm which processes decode untrusted Brotli, and make the restart step explicit in your patch runbook. Then the next library-level CVE in this class — and there will be one — is a query you already know how to run. That is the argument for treating this as continuous threat exposure management rather than an incident.
A synthetic composite, illustrative only. A mid-market SaaS platform runs its API on the distribution-built Node.js in Ubuntu 26.04 — which is Node.js 22.22.1, a version number below upstream's fixed 22.23.4, and marked "Not affected" by Ubuntu because it links the system Brotli. The scanner flagged the version gap. The team closed it as a false positive. Both readings were half right, and neither one updated the `brotli` package. Meanwhile an internal link-preview service fetches customer-supplied URLs and decompresses the responses, which is the one component in the estate that certainly decodes untrusted Brotli, and a .NET 6 reporting service on the same subnet sits on a package whose vendor has deferred a fix pending a determination of whether it is impacted at all.
None of that is visible from a version report. All of it is visible from asking which processes decode what, and from whom.
That is the distinction ioSENTRIX is built around: not confirming that a patch was applied — your pipeline already told you that, and here it told you something true and nearly useless — but establishing whether the vulnerable code path is reachable in your deployment. Reachability is the finding. A version string is a precondition for one.
Scoping that work is ordinary web application penetration testing discipline applied to a library rather than a feature, and memory-corruption testing needs its rules of engagement agreed in advance, because the realistic outcome of a genuine attempt against a production service is a crash. It also needs the inventory to exist first, which is the unglamorous part most estates are missing — the same gap that makes an AI bill of materials hard to produce for model dependencies is what makes a Brotli inventory hard to produce for native ones. Getting the patch and release pipeline to carry library-level facts rather than package names is the durable fix; the application security fundamentals have not changed, only the layer the question lands on.
The gap this CVE exposes is the one between a library fix landing upstream and your estate knowing it has that library. Closing it is an inventory problem before it is a testing problem.
Is CVE-2026-111497 a Node.js vulnerability or a Brotli vulnerability? A Brotli vulnerability. CISA catalogs it under Google Brotli, the fix originates in the upstream Brotli releases v1.2.1, v1.1.1 and v1.0.10, and Node.js is affected because it ships or links that decoder. Red Hat's bulletin names Firefox, Thunderbird, the Python Brotli bindings and a JBoss package as affected consumers too, and Microsoft shipped separate .NET updates.
I patched Node.js. Am I safe? Only if your Node.js build carries a bundled Brotli. If it links the system library — which is how Red Hat builds the `nodejs:22` module on RHEL 8 and 9, and how Ubuntu builds `nodejs` on 22.04 and later — the fix you need is an updated `brotli` / `libbrotli` / `libbrotlidec1` package, depending on your distribution, plus a restart of every process that had the old library mapped.
Is my web server exposed because it serves Brotli-compressed responses? Not by that alone. The vulnerability is in the decoder, and compressing a response does not exercise it. Exposure requires that something decompresses Brotli data supplied by someone else. That said, Red Hat's bulletin advises stripping or rejecting `Content-Encoding: br` at the reverse proxy in both directions until the system package is updated, so treat negotiating the encoding with untrusted peers as a reason to look closer.
Is the score 8.1 or 9.8? Both are published. Red Hat gives 8.1 and rates the issue Important; NVD gives 9.8; a CVSS 4.0 base of 9.2 also circulates. The difference between the two v3.1 scores is entirely Attack Complexity. None of the numbers tells you whether the vulnerable path is reachable in your deployment, which is the question that should drive your triage.
Was this exploited in the wild? CISA added it to the Known Exploited Vulnerabilities catalog on 27 October 2026 — a catalog CISA describes as covering known exploited vulnerabilities that carry significant risk to the federal enterprise. No primary source we could read publishes indicators, attack telemetry or a working proof of concept. Treat the exploitation claim as established and the detection story as unsupported.
ioSENTRIX is a CREST-accredited penetration testing firm, ISO/IEC 27001 certified and SOC 2 Type 2 attested. On issues like this one our work is reachability testing: which of your services decode data from outside your trust boundary, which decoder those processes are actually running, and whether a crafted input reaches the vulnerable path from where an attacker stands. Independent adversarial testing is what turns a version report into evidence, whoever performs it.
This CVE is a good test of your own exposure process, and many organizations will fail it in a specific, fixable way: they will have patched the thing that was named rather than the thing that was vulnerable.
So a self-check, drawn from the six questions above. Can you list, today, every process in your estate that decompresses Brotli data it did not produce? For each, do you know whether its decoder is bundled or shared — and have you looked past the runtime you were told about, to the browsers, Python bindings and .NET runtimes on the same hosts? Has every one of those processes restarted since you patched?
If the first question alone requires a research project, that — not this CVE — is the finding worth acting on.
If you want it answered with evidence rather than inference, talk to us. The federal due date for this one is 10 November 2026, which is a reasonable deadline to borrow even if it does not apply to you.