threat_intelligence2777 wordsRead on Huntaegis

Node2Shell evolves to HTTP2Shell. Brotli flaw (CVE-2026-111497) blast radius affects many libraries & apps using HTTP.

TL;DR ⚠️ Brotli is a widely used compression library from Google. On Wednesday, October 21st NodeJS disclosed CVE-2026-111497, dubbed “node2shell,” wherein a Node.js process that decompresses attacker-controlled Brotli data can be made to leak memory or run arbitrary code. On Thursday, Python disclosed that Python packages were vulnerable to CVE-2026-111497 as well. On Friday, October 23rd, it has become known that this CVE affects other major languages and service applications using HTTP, where patches are not yet fully available. Another popular term: "Broccoli2Shell." Check if you are decoding Brotli as a dependency within your libraries. Stay on guard for wider announcements and be ready to upgrade as soon as possible. If there is no patch available for a library or application that may be affected, we recommend disabling Brotli decoding until patches become available. Update 4:12PM PT: Patches are available for libbrotli, Python, C++, NodeJS, bun, Envoy and more coming. Apache and Nginx do not decode brotli by default. Update 4:15 PM PT: OpenAI shares that they discovered this vulnerability in February. While the root cause issue was fixed in the Brotli source code at the time, it wasn’t known that it gave rise to a security vulnerability. OpenAI's advisory is here. What is Brotli? Brotli is a lossless compression algorithm and data format developed by Google. It’s a way to make data smaller for storage or sending over the internet. Software then unpacks it to recover the original data. It’s widely used for HTTP compression to compress web content such as HTML, CSS, and JavaScript. What is CVE-2026-111497? CVE-2026-111497 is an out-of-bounds write in the Google Brotli decoder affecting versions 1.0.3 through 1.2.0 on all platforms. This is the same Brotli decoder flaw behind Node2Shell announced a couple days ago. A remote, unauthenticated attacker can send a crafted Brotli-compressed stream to corrupt memory, leak sensitive data, crash the process, or potentially execute arbitrary code. It carries a CVSS v4.0 score of 9.2 (Critical), and Node.js is affected through its bundled Brotli library. A bug makes the Brotli decoder keep accepting more bytes when it should reject the data. Those bytes can overflow a small working buffer and damage the program’s memory. An attacker can use that damage to control what runs, such as their own code. OpenAI found this in February and reported it as unauthenticated remote code execution that works in both directions, so a malicious client can take over an unpatched server and a malicious server can take over an unpatched client that accepts compressed responses. The root cause was fixed in the Brotli source code in February, but it wasn't recognized as a security issue at the time and no release shipped with the fix until now. That means every project that bundles Brotli has to ship its own update. You can see what we’ve tracked here in Aikido Intel. As for unaffected software, Apache’s standard mod_brotli does not decode Brotli. How to patch HTTP2Shell CVE-2026-111497 For CVE-2026-111497, update the affected runtime or Brotli library: - Node.js: upgrade to 22.23.4, 24.22.1, or 26.12.1, or a newer supported release in the corresponding release line. - Native Brotli / libbrotli: upgrade to 1.2.1 or later. For older release lines, use patched 1.0.10 or 1.1.1. - Python packages: upgrade Brotli to 1.2.1 or later and brotlicffi to 1.2.1.0 or later, wherever installed. - curl / libcurl: update its Brotli dependency to 1.2.1, a patched older release, or the vendor’s security-fixed package. Bundled or statically linked copies require an updated application build. - Bun: upgrade to 1.4.4 or later. Rebuild compiled executables that bundle Bun. - Envoy: upgrade to 1.40.0, 1.39.3, 1.38.6, or 1.37.8, or a newer release in a supported branch. 1.36.12 also includes the fix, but the 1.36 branch is unsupported. - Istio: the fix is included in 1.29.9, 1.30.6, and 1.31.2. Use a newer supported release in the corresponding line; the 1.29 branch is end of life. - Operating-system packages: install the vendor’s security update. Vendors may backport the fix without changing the upstream version number. - Other HTTP servers, reverse proxies, API gateways, and HTTP clients: update the affected runtime or Brotli library they use. Where Brotli is bundled into the product, install the product vendor’s release that explicitly addresses this CVE. For managed services, confirm remediation with the provider. Update dependency locks, rebuild affected applications and container images, redeploy, and restart services. Verify that running workloads use the patched components. | Project | Patch status | Fixed versions | Notes | |---|---|---|---| | Node.js | Patch available | 22.23.4 · 24.22.1 · 26.12.1 | Use a supported release line. | | Bun | Patch available | 1.4.4 | Includes Brotli 1.2.1. | | Envoy | Patch available | 1.40.0 · 1.39.3 · 1.38.6 · 1.37.8 | 1.36.12 also includes the fix, but 1.36 is unsupported. Use a supported branch. | | Istio | Patch available | 1.29.9 · 1.30.6 · 1.31.2 | 1.29 is end of life, so move to a supported line. | | Google Brotli (upstream) | Patch available | 1.0.10 · 1.1.1 · 1.2.1 | Choose the fixed release for your library branch. | What to do if you can't upgrade yet These workarounds reduce exposure while you prepare the upgrade: - Incoming HTTP requests: reject requests whose Content-Encoding includes br at the reverse proxy, load balancer, or application middleware, before any vulnerable decoder processes the body. Match br case-insensitively, including within lists of encodings. - Outbound HTTP requests: remove br from Accept-Encoding. Also disable Brotli response decoding or reject responses whose Content-Encoding includes br before decoding begins. Ensure this check occurs before automatic body processing; checking after the client has downloaded and decoded the response is too late. Changing Accept-Encoding alone is insufficient: a malicious server can send a Brotli response regardless of what the client advertises, and urllib3 selects its decoder from the response’s Content-Encoding header. Keep these controls in place until affected components are patched and verified. Review coverage as vendors confirm additional affected components or attack paths. How to disable Brotli decoding while you patch If you can't upgrade every affected component right away, turning off Brotli decoding cuts off the path to the vulnerable decoder. Each tool handles this differently, and blocking Brotli in one place doesn't protect the others. curl and libcurl curl only decodes compressed responses when you pass --compressed . Remove the flag from scripts, aliases, CI jobs, and .curlrc files. Setting an Accept-Encoding header yourself with -H doesn't turn decoding on. In apps that use libcurl, leave CURLOPT_ACCEPT_ENCODING at its default of NULL, which stops libcurl from decompressing responses. Setting it to a list like "gzip, deflate" won't protect you, because a malicious server can respond with Brotli regardless of what the client asks for. To check whether your curl build can decode Brotli at all, run curl -V and look for brotli in the Features line. Python Where Brotli support is optional, uninstall Brotli and brotlicffi, remove extras such as httpx[brotli] and any other requirements that would reinstall them, regenerate your lockfiles, and rebuild and restart your workloads. Requests, urllib3, and HTTPX keep gzip and deflate support without these packages, but a server that sends Brotli anyway may cause an unreadable response or an application error. Uninstalling the packages also leaves any Brotli decoders bundled into other runtimes, libraries, or products in place. Node.js and Bun Reject requests whose Content-Encoding includes br in middleware or at your proxy, before Express 5 or body-parser 2.x decodes the body. fetch() decodes Brotli responses automatically and doesn't offer a standard setting to turn that off, so upgrading the runtime is the only fix for responses your app fetches. Envoy and Istio Envoy only decodes Brotli when the Brotli decompressor filter is configured, which Istio doesn't do by default. To find it in your EnvoyFilters, run: kubectl get envoyfilters -A -o yaml | grep -nE 'compression\.brotli\.decompressor|brotli\.decompressor\.v3\.Brotli' To check a running sidecar or gateway, run: istioctl proxy-config listeners -n -o json | grep -nE 'compression\.brotli\.decompressor|brotli\.decompressor\.v3\.Brotli' If either command returns a match, remove the Brotli decompressor from the EnvoyFilter and run the second command again to confirm it's gone from the live proxy configuration. Using Brotli only to compress responses doesn't trigger the vulnerable code. Apache mod_brotli compresses responses and doesn't decode them, so a standard Apache setup doesn't run the vulnerable decoder. How Aikido helps with CVE-2026-111497 Aikido flags vulnerable versions of Brotli and brotlicffi in your repositories, container images, and dependencies, including when they arrive as transitive dependencies. Your dashboard shows which services still run a vulnerable version, so you can upgrade the ones that call outside servers or accept compressed request bodies first. Once you've upgraded, Aikido checks if the finding is gone. The timeline Brotli is a widely used compression library from Google. On Wednesday, October 21st NodeJS disclosed CVE-2026-111497, dubbed “node2shell,” wherein a Node.js process that decompresses attacker-controlled Brotli data can be made to leak memory or run arbitrary code. Users were exposed if their app or a library decompresses bad Brotli data (e.g. the built-in fetch(), body-parser). The next day, Python released a security update that patches the same flaw; Python packages were also vulnerable to CVE-2026-111497. Brotli flaw may affect even more languages and service applications, given how widely integrated the library is downstream. It turns out OpenAI had found this back in February. Technical details of CVE-2026-111497 The flaw sits in DecodeBlockTypeAndLength() , which handles block switches, the points where a Brotli stream changes which Huffman tree it uses. In vulnerable versions the function returns a plain boolean, and BROTLI_FALSE can mean either "this stream is malformed" or "I need more input." Callers can't tell the two apart, and on the fast path the decoder discards the return value entirely. A crafted stream can declare a single block type and then exhaust that block's length, which forces a switch that can't succeed. The decoder then either reports that it needs more input for a stream that's complete, or keeps decoding with the block state it already had. That second path leads to the out-of-bounds write. The upstream fix, google/brotli commit 0ed4268, makes the function return an error code and adds a new error, BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (-17). Decoding now stops on a format error on both the safe and fast paths. OSM diffed the Brotli 1.2.0 and 1.2.1 source distributions and found that 1.2.1 differs only in the version bump and the decoder changes from that commit. Brotli vulnerabilities in Python libraries (CVE-2026-111497) OpenSourceMalware (OSM) did early research into how this flaw reaches Python, including diffing the patched releases and testing the decoder with AddressSanitizer. Their write-up is worth reading for the full details. The Brotli flaw behind Node2Shell (CVE-2026-111497) affects Python. Two PyPI packages, Brotli and brotlicffi, compile the same vulnerable Brotli decoder that Node.js bundles. GitHub published an advisory for the CVE. Brotli has 82.8 million downloads per month. You're affected if any Python environment you run has Brotli 1.2.0 or earlier, or brotlicffi 1.2.0.x, installed. Popular HTTP clients such as requests and httpx load these packages automatically when they're present. Some packages automatically install Brotli as a dependency such as Scrapy, while others require explicit mention of it. An attacker can reach the vulnerable decoder by sending a malicious Brotli response to a request your app makes, or by sending your app a request body compressed with Brotli. That means an app can be exposed without importing Brotli anywhere in its own code. It’s a popular transitive dependency, so check your systems. To fix it, upgrade to the patched releases: - Brotli -> 1.2.1 - brotlicffi -> 1.2.1.0 Who is affected by CVE-2026-111497 in Python? You’re affected if any of your Python environments have one of these packages installed: | Package | Affected versions | Fixed version | |---|---|---| | Brotli (PyPI) | 1.2.0 and earlier | 1.2.1 | | brotlicffi (PyPI) | 1.2.0.x | 1.2.1.0 | Your code doesn’t have to import either package. These HTTP clients advertise Accept-Encoding: br and decode Brotli responses automatically: - urllib3 (and therefore requests) when Brotli or brotlicffi is installed - httpx with the brotli extra - aiohttp when Brotli is installed - Scrapy, and anything built on the clients above Attacker data can reach the decoder through two routes: - Outbound requests. Your app fetches a Brotli response from a server an attacker controls, such as through a webhook delivery, URL preview, crawler or “fetch this URL” feature. - Inbound requests. Your framework or middleware decodes a request body sent with Content-Encoding: br, which is the Python equivalent of the Express 5 case in Node.js. How to fix CVE-2026-111497 in Python The fix is a package upgrade, and it takes four steps: - Upgrade whichever package you have installed with pip install -U "Brotli>=1.2.1" or pip install -U "brotlicffi>=1.2.1.0". If you use a lockfile with Poetry, uv, or pip-tools, update the constraint and regenerate the lockfile. - Rebuild your container images and any wheels that bundle either package. An image built on a vulnerable version stays vulnerable until you rebuild it. - Check every environment you run, including laptops, CI runners, servers and containers. Many projects pull in Brotli through an HTTP client extra, so look at your full resolved dependency tree. - Confirm your scanner flags them. Aikido detects vulnerable versions of both packages, and the PyPI security team has published PYSEC-2026-4322 for Brotli and PYSEC-2026-4323 for brotlicffi, so tools that read the PyPI advisory database should flag them too. If your Python Brotli bindings came from a Linux distribution package instead of PyPI, the fix comes through your distribution, so check its security advisory as well. What is the Python Brotli vulnerability (CVE-2026-111497)? Python Brotli vulnerability refers to CVE-2026-111497, the Brotli decoder flaw known as Node2Shell, as it affects Python packages on PyPI. The CVE record pairs CWE-252 (unchecked return value) with CWE-787 (out-of-bounds write). How serious is CVE-2026-111497 for Python, and is it being exploited? The CVE record gives the flaw a CVSS 4.0 score of 9.2, and Node.js rates it high severity. OSM built Brotli 1.2.0 and 1.2.1 with AddressSanitizer and ran a crafted stream through both. Version 1.2.0 consumed all of the roughly 23 MB stream and kept reporting that it needed more input, whether the stream arrived in one piece or in chunks as small as one byte. Version 1.2.1 rejected the stream with error -17 every time. OSM didn't pursue memory corruption or code execution in the Python extension. The decoder code is the same code that researchers exploited against an unmodified Node.js 24.22.0 build, as Imperva and others reported. For Node.js, The Hacker News reported no exploitation in the wild as of October 22. Treat it as urgent anyway. The bug is a memory-safety flaw in a component that handles untrusted network input, and the fix is a routine version bump. Services that call outside servers or accept compressed request bodies should go first. How to check if your Python app is exposed - Check installed versions with pip show Brotli brotlicffi in each environment, and with docker run --rm pip show Brotli brotlicffi for each container image. - Find what pulls the packages in. Run pipdeptree -r -p Brotli to see which dependencies require it, and search your lockfiles with grep -i brotli poetry.lock uv.lock requirements*.txt. - List the outbound HTTP calls that go to servers you don't control, and any endpoints that decode Content-Encoding: br request bodies. - Upgrade the services that match step 3 first, then the rest. If you're reproducing the bug from Python, brotli.decompress() raises a generic brotli.error: decoder failed for any error, so you can't see which error code fired. A Decompressor() fed the crafted stream incrementally will never finish on 1.2.0. FAQ Which versions fix CVE-2026-111497 in Python? Brotli 1.2.1 and brotlicffi 1.2.1.0, along with any newer releases. Do I need to import Brotli in my code to be affected? An installed package is enough. urllib3, requests, httpx and aiohttp use Brotli or brotlicffi automatically when either is present and decode Brotli responses from any server your app calls. Will pip-audit or Dependabot flag this? It should now. pip-audit reads the PyPI advisory database, which includes PYSEC-2026-4322 for Brotli and PYSEC-2026-4323 for brotlicffi, and OSV now maps the GitHub advisory that Dependabot uses to both packages. Aikido also flags both, including when they arrive as transitive dependencies. Is there a workaround? Uninstalling Brotli and brotlicffi removes the vulnerable decoder from Python, though a server that sends Brotli anyway may cause errors. Rejecting Brotli-encoded requests at the edge reduces inbound exposure but doesn't protect against Brotli responses your app fetches. For steps covering other tools, see "How to disable Brotli decoding while you patch."

How it works

Once you click Generate, Ollama reads this article and crafts 5 comprehension questions. Your answers are graded against the article content — general knowledge won't be enough. Score 70+ to count toward your certificate.

Questions are cached — you'll always get the same 5 for this article.