CVE-2026-111497 is a memory-corruption bug in Google’s Brotli decompressor. Upstream versions 1.0.3 through 1.2.0 are affected, and 1.0.10, 1.1.1 and 1.2.1 fix it. CISA added it to the Known Exploited Vulnerabilities catalog on October 27, 2026, with a federal remediation date of November 10. The hard part is not the patch. Brotli is compiled into Node.js, Python wheels, Go modules, proxies and service meshes, and several patched builds still report the old version number. Here is where it hides, what “fixed” looks like for each, and a tested way to check code you vendor yourself.
Are you affected?
You are exposed if a vulnerable Brotli decoder processes data an attacker can supply. The CVE record says an attacker with “a crafted Brotli-compressed stream” can “corrupt adjacent decoder state memory, disclose sensitive memory contents, cause a denial of service, or potentially execute arbitrary code”. Google’s CNA scored it CVSS 4.0 9.2 (Critical). The Node.js project rates its copy High.
| Where Brotli lives | Affected | Fixed in | How to check | Source |
|---|---|---|---|---|
| Google Brotli / libbrotli | 1.0.3 to 1.2.0 | 1.0.10, 1.1.1, 1.2.1 | Package version, or the code check below for vendored copies | CVE record, upstream CHANGELOG |
| Node.js 22, 24, 26 | Earlier builds on those lines | 22.23.4, 24.22.1, 26.12.1 | node -v (not process.versions.brotli) | Node.js advisory |
| End-of-life Node.js | Assume affected | None: upgrade | node -v | Node.js advisory |
Python Brotli | 1.0.3 to 1.2.0 | 1.2.1 | pip show Brotli | Aikido; PyPI release date |
Python brotlicffi | 1.2.0.x | 1.2.1.0 | pip show brotlicffi | Aikido; PyPI release date |
Go github.com/andybalholm/brotli | Before v1.2.7 | v1.2.7 | go list -m github.com/andybalholm/brotli | CVE record reference, source diff |
| Envoy | 1.36.11, 1.37.7, 1.38.5, 1.39.2 | 1.36.12, 1.37.8, 1.38.6, 1.39.3, 1.40.0 | envoy --version | Wiz (qualified); we checked 1.39.2 against 1.39.3 |
| Istio | 1.29.0 to 1.29.8, 1.30.0 to 1.30.5, 1.31.0 to 1.31.1 | 1.29.9, 1.30.6, 1.31.2 | istioctl version | Wiz (qualified) |
| Bun | 1.0.21 to 1.4.3 | 1.4.4 | bun --version | Wiz (qualified) |
| Distro packages (libbrotli1, brotli) | Depends on backport | Distro security update | Your distro’s security tracker | — |
The Envoy, Istio and Bun ranges come from Wiz’s write-up, not from those projects’ advisories. We did not read those advisories directly. For Envoy we checked the source instead: bazel/repository_locations.bzl pins Brotli 1.2.0 at tag v1.39.2, while v1.39.3 pins a Brotli commit whose decode.c contains the fix.
Linux distributions usually backport fixes and keep the upstream version. Our Ubuntu 24.04 sandbox, for example, has libbrotli1 1.1.0-2ubuntu0.1. That string alone does not tell you whether the fix is in. Use your distribution’s security tracker for the CVE.
Why the version string can mislead you
Node.js patched its bundled Brotli in place. On the fixed Node.js 22.23.4 the reported library version is still the old one:
$ node -v
v22.23.4
$ node -p process.versions.brotli
1.1.0
We ran that in our sandbox. The source tree agrees: deps/brotli/c/common/version.h declares 1.1.0 at both v22.23.3 and v22.23.4, and 1.2.0 at v24.22.1 and v26.12.1, but only the fixed tags contain the patched decoder (v22.23.3 and v24.22.0 do not). A scanner that flags process.versions.brotli < 1.2.1 will raise false positives on fixed Node.js. A scanner that trusts a vendored version.h can miss real exposure the other way round. For Node.js, use the Node.js version. For anything else you vendor, check the code.
What the bug is
The Node.js advisory gives the clearest description: “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.”
The upstream diff between v1.2.0 and v1.2.1 of c/dec/decode.c shows exactly that. DecodeBlockTypeAndLength() used to return a plain boolean, so “invalid stream” and “need more input” looked the same, and the non-safe callers ignored the result altogether (static void DecodeLiteralBlockSwitch(...)). After the fix the function returns a BrotliDecoderErrorCode, emits BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH for the invalid case, and every caller checks it through a new BROTLI_SAFE_WITH_STATUS macro. That matches the two weaknesses in the CVE record: CWE-252 (unchecked return value) and CWE-787 (out-of-bounds write).
The flaw was found by Khai Tran and Sylvie Mayer of OpenAI Codex Security, who are credited in both the CVE record and the Node.js advisory.
Where untrusted Brotli reaches your code
The flaw is in decompression, so look for places that decode data you did not produce:
- Request bodies. Any endpoint or middleware that inflates
Content-Encoding: bruploads. - Outbound HTTP. HTTP clients decode Brotli responses for you. If an attacker controls or can redirect the URL (webhooks, link previews, feed fetchers, scrapers), they control the compressed bytes.
- Files and archives that contain Brotli streams.
- Proxies and meshes that decompress traffic to inspect or transform it.
Two behaviours we checked, because they mean code that never mentions Brotli can still run it:
- Node.js
fetch()decodes Brotli it never asked for. On Node.js 22.23.4,fetch()sentaccept-encoding: gzip, deflate. When our local test server replied withcontent-encoding: br,fetch()decompressed the body anyway. A hostile server can choose Brotli whatever the client advertises. - Python’s requests turns Brotli on when it is installed. urllib3’s
util/request.pyappendsbrto its defaultAccept-Encodingwhenbrotlicffiorbrotlican be imported. With Brotli 1.2.1 installed,requests.utils.default_headers()returnedgzip, deflate, brin our test. The decoding then runs in whichever Brotli package is installed.
What to do now
- Update the runtimes. Node.js to 22.23.4, 24.22.1 or 26.12.1 or later. Move off end-of-life Node.js lines: the advisory notes that “End-of-Life versions are always affected when a security release occurs.”
- Update language packages in every lockfile and image:
Brotli>=1.2.1,brotlicffi>=1.2.1.0,github.com/andybalholm/brotli v1.2.7. Both Python fixes were published to PyPI on October 22, 2026. - Update proxies and meshes (Envoy, Istio) and Bun to the fixed releases above. Confirm the ranges against each project’s own advisory.
- Apply distro updates for
libbrotli/brotli, then restart the long-running processes that loaded the old library. - Rebuild container images. A fixed base image does not help a running container that was built from the old one.
- Hunt for vendored copies with the check below.
If you cannot patch a service today, reduce what it decodes. As a stopgap, reject Content-Encoding: br request bodies at the edge for services that do not need them, and stop server-side fetchers from decoding responses from untrusted URLs. This is our editorial suggestion, not vendor guidance, and it does not replace the update.
Inventory commands
# Node.js: the version that matters
node -v
# Python: every environment and image
pip show Brotli brotlicffi 2>/dev/null | grep -E '^(Name|Version)'
pipdeptree -r -p Brotli # who pulls it in
# Go modules
go list -m all | grep andybalholm/brotli
# Debian/Ubuntu and RHEL-family system libraries
dpkg -l 'libbrotli*' 2>/dev/null | awk '/^ii/{print $2, $3}'
rpm -q brotli libbrotli 2>/dev/null
The pip, node and dpkg lines were run in our sandbox. The go, pipdeptree and rpm lines are standard tool usage that we did not run here.
Checking vendored source for the fix
C and C++ projects often copy c/dec/decode.c into their tree, and Go programs carry decode.go in the module cache or a vendor/ directory. This script looks for the patched function signature instead of trusting any version string:
#!/bin/sh
# brotli-fixcheck.sh DIR...: find vendored Brotli decoder sources and report
# whether they carry the CVE-2026-111497 fix. Looks at the code, not the
# version string, because patched Node.js still reports the old version.
for root in "$@"; do
find "$root" \( -name decode.c -path '*dec*' \) -o \( -name decode.go -path '*brotli*' \) 2>/dev/null |
while read -r f; do
if grep -q 'BrotliDecoderErrorCode DecodeBlockTypeAndLength' "$f" ||
grep -q 'func decodeBlockTypeAndLength(.*) int {' "$f"; then
echo "PATCHED $f"
elif grep -q 'DecodeBlockTypeAndLength\|decodeBlockTypeAndLength' "$f"; then
echo "VULNERABLE $f"
fi
done
done
We tested it against 12 sources pulled from GitHub: upstream Brotli v1.0.9, v1.0.10, v1.1.0, v1.1.1, v1.2.0 and v1.2.1; Node.js deps/brotli at v22.23.3, v22.23.4, v24.22.0 and v24.22.1; and andybalholm/brotli v1.2.6 and v1.2.7. It reported every fixed release as PATCHED and every earlier one as VULNERABLE. Run it over source trees, vendor/ directories and $(go env GOMODCACHE).
It cannot inspect compiled binaries, and a heavily modified fork may not match either pattern. Treat “no output” as “no recognisable copy found”, not as “safe”.
What to hunt for
No vendor or agency has published indicators of compromise for this CVE, and CISA’s KEV entry does not require forensic triage (forensicTriage: No). Practical checks:
- Crashes. Segfaults or aborts in Node.js, Python or proxy processes since late October, especially in services that fetch remote content or accept compressed uploads.
- Unexpected Brotli. Requests with
Content-Encoding: brto endpoints that never receive compressed bodies. Wiz recommends reviewing WAF, application and network logs for suspicious Brotli-compressed traffic. - Outbound fetches from services that took user-supplied URLs, close in time to a crash.
Limits of this article
We did not reproduce the memory corruption or test any exploit. Our checks cover version strings, source code and HTTP client behaviour in a sandbox: Node.js 22.23.4, Python with Brotli 1.2.1, Ubuntu 24.04. The Envoy, Istio and Bun ranges come from a security vendor’s summary. The list of affected software is not complete. Wiz notes that other products that bundle or link vulnerable versions of the Brotli C decoder may also be affected.
For the wider process of keeping dependency updates moving, see dependency audits without slowing down releases. For publishing or reading “not affected” statements about a library like this, see VEX explained. Last week’s PHP2Shell patch-and-hunt guide covers the two PHP runtime flaws CISA added to KEV the day before.
Sources and verification
| Important claim | Source | Status |
|---|---|---|
| Affected 1.0.3–1.2.0; fixed 1.0.10, 1.1.1, 1.2.1; CVSS 4.0 9.2; CWE-252/787; credit | CVE-2026-111497 record (cvelistV5) | Verified |
| KEV added 2026-10-27, due 2026-11-10, forensicTriage No; SSVC exploitation active | CISA KEV data; CISA ADP in the CVE record | Verified |
| 1.2.1 released 2026-10-21 with the CVE fix; code change | google/brotli CHANGELOG; c/dec/decode.c v1.2.0 vs v1.2.1 | Verified |
| Node.js fixed releases, root cause, EOL statement | Node.js October 2026 security releases | Verified |
| Patched Node.js reports the old Brotli version | node -p process.versions.brotli on v22.23.4; deps/brotli at the listed tags | Verified (our test) |
| Go fix in andybalholm/brotli v1.2.7 | Release v1.2.7; decode.go v1.2.6 vs v1.2.7 | Verified |
| Python Brotli 1.2.1, brotlicffi 1.2.1.0 | Aikido; PyPI upload dates 2026-10-22 | Verified |
urllib3/requests advertise br when Brotli is installed | urllib3 util/request.py; our test | Verified |
| Envoy, Istio, Bun ranges | Wiz; Envoy repository_locations.bzl at v1.39.2/v1.39.3 | Qualified |
| Envoy and other consumers affected | oss-security, 2026-10-23, 2026-10-24 | Verified |
Frequently asked questions
Is CVE-2026-111497 being exploited?
CISA added it to the Known Exploited Vulnerabilities catalog on October 27, 2026, and its CVE record rates exploitation as 'active'. Neither CISA nor the vendors have published details of the attacks. Wiz writes that researchers have demonstrated exploitation against unpatched Node.js.
My Node.js says process.versions.brotli is 1.1.0. Am I vulnerable?
Not necessarily. Node.js applied the fix to its bundled copy without changing the version string. Node.js 22.23.4 reports Brotli 1.1.0 but contains the fix. Go by the Node.js version: 22.23.4, 24.22.1 or 26.12.1 and later are fixed.
Does this affect web servers that only compress responses?
The flaw is in the decoder. Compressing your own responses does not decode untrusted data. Risk comes from decompressing data someone else controls: request bodies, upstream or third-party responses, or files. Patch anyway: many servers and proxies link the full library.
Which Python packages do I need to update?
Brotli to 1.2.1 and brotlicffi to 1.2.1.0. Both build the Brotli C decoder. requests, urllib3 and other HTTP clients use whichever one is installed, so updating these two packages covers those clients too.
Vulnerability ManagementSupply ChainNode.jsPythonRemote Code Execution
