---
id: "CVE-2026-111497"
kind: "vulnerability"
aliases: ["CVE-2026-111497"]
title: "Brotli: crafted compressed stream overflows buffer, enables remote code execution"
severity: "critical"
cvss: 9.2
epss: 0.0048
exploited: false
status: "open"
category: "package"
products: [{"name": "brotli", "fixed": ["1.0.10", "1.1.1", "1.2.1"], "affected": ">= 1.0.3, < 1.0.10; >= 1.1.0, < 1.1.1; >= 1.2.0, < 1.2.1", "ecosystem": "vendor"}, {"name": "node", "fixed": ["22.23.4", "24.22.1", "26.12.1"], "affected": "22.x < 22.23.4; 24.x < 24.22.1; 26.x < 26.12.1; EOL lines (25.x, 23.x, <=20.x) unfixed", "ecosystem": "npm"}, {"name": "Brotli", "fixed": ["1.2.1"], "affected": "<= 1.2.0", "ecosystem": "pypi"}, {"name": "brotlicffi", "fixed": ["1.2.1.0"], "affected": "<= 1.2.0.x", "ecosystem": "pypi"}, {"name": "bun", "fixed": ["1.4.4"], "affected": "< 1.4.4", "ecosystem": "npm"}]
ecosystems: ["npm", "pypi", "vendor"]
tags: ["brotli", "bun", "cloudflare", "docker", "envoy", "express", "http-compression", "istio", "lab-disclosure", "node.js", "openai", "package", "poc-public", "pypi", "python", "self-hosted"]
not_affected_if: ["brotli-decoding-disabled", "compress-outgoing-only", "patched-versions"]
published_at: "2026-10-22T14:17:37+00:00"
first_seen_at: "2026-10-23T21:57:31+00:00"
updated_at: "2026-10-25T01:23:50+00:00"
sources: [{"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-111497", "first_seen_at": "2026-10-23T21:57:31+00:00"}, {"source": "analyst", "url": null, "first_seen_at": "2026-10-23T22:49:07+00:00"}, {"source": "lab", "url": "https://patchtheplanet.org/brotli", "first_seen_at": "2026-10-24T00:12:39+00:00"}, {"source": "github-poc", "url": "https://github.com/mahumadad/CVE-2026-111497-assessment", "first_seen_at": "2026-10-24T03:31:37+00:00"}, {"source": "epss", "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-111497", "first_seen_at": "2026-10-24T07:15:51+00:00"}, {"source": "github-poc", "url": "https://github.com/googlesky/CVE-2026-111497", "first_seen_at": "2026-10-24T07:18:28+00:00"}, {"source": "github-poc", "url": "https://github.com/pt-act/node2shell-cve-2026-111497", "first_seen_at": "2026-10-24T10:05:10+00:00"}, {"source": "github-poc", "url": "https://github.com/s1ko/poc-cve-2026-111497", "first_seen_at": "2026-10-24T10:50:41+00:00"}, {"source": "github-poc", "url": "https://github.com/tc4dy/CVE-2026-111497-Toolkit", "first_seen_at": "2026-10-24T15:23:20+00:00"}, {"source": "github-poc", "url": "https://github.com/mnk-works/cve-2026-111497-rce-checker", "first_seen_at": "2026-10-24T22:31:28+00:00"}, {"source": "github-poc", "url": "https://github.com/syrex1013/CVE-2026-111497-node2shell", "first_seen_at": "2026-10-24T23:16:44+00:00"}, {"source": "lab", "url": "https://developers.cloudflare.com/changelog/post/2026-10-25-emergency-waf-release/", "first_seen_at": "2026-10-25T01:12:28+00:00"}]
---

# Brotli: crafted compressed stream overflows buffer, enables remote code execution

Google's Brotli decoder, used by Node.js, Bun, Python bindings and proxies, overflows a memory buffer when it reads a crafted compressed stream. An attacker who can send compressed data to an affected service can corrupt memory, crash it, read memory, or run code.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- vendor:brotli affected >= 1.0.3, < 1.0.10; >= 1.1.0, < 1.1.1; >= 1.2.0, < 1.2.1 fixed 1.0.10, 1.1.1, 1.2.1
- npm:node affected 22.x < 22.23.4; 24.x < 24.22.1; 26.x < 26.12.1; EOL lines (25.x, 23.x, <=20.x) unfixed fixed 22.23.4, 24.22.1, 26.12.1
- pypi:Brotli affected <= 1.2.0 fixed 1.2.1
- pypi:brotlicffi affected <= 1.2.0.x fixed 1.2.1.0
- npm:bun affected < 1.4.4 fixed 1.4.4

## How to check

- Run `node --version` and `bun --version`, then compare against the fixed versions below.
- Run `pip show Brotli` and `pip show brotlicffi`, and check bundled wheels and static binaries.
- Look for `Content-Encoding: br` handling in web servers, body parsers, HTTP clients and Envoy or Istio Brotli decompressor filters.

## Fix

- Node.js: move to `22.23.4`, `24.22.1` or `26.12.1`; lines 25.x, 23.x and 20.x or older have no fix, so move to a supported line.
- Bun: move to `1.4.4` or later.
- Brotli library: `1.0.10`, `1.1.1` or `1.2.1` for its branch; Python `Brotli` `1.2.1` and `brotlicffi` `1.2.1.0`.
- Envoy Proxy `1.40.0`, `1.39.3`, `1.38.6` or `1.37.8`; Istio `1.29.9`, `1.30.6` or `1.31.2`. Until patched, reject `Content-Encoding: br` before any decoder runs.

## Mitigated for you by

- Team (workaround): covers Requests with Content-Encoding: br rejected before any proxy, middleware, or body parser decompresses them, including direct-to-origin and alternate routes Limits: Does not cover a proxy that decodes requests first unless it is also guarded, or non-HTTP decoding paths Still: Reject requests with Content-Encoding: br before any decoding while keeping gzip, deflate, or other supported codecs enabled https://patchtheplanet.org/brotli
- Team (workaround): covers Brotli responses rejected before decoding when the client supports checking the encoding first Limits: Removing br from Accept-Encoding alone does not stop a server from sending Brotli; checks after an automatic body read can be too late Still: Disable automatic Brotli decompression in HTTP clients, or pause the affected fetch, or use a patched client https://patchtheplanet.org/brotli
- Team (workaround): covers Request bodies with Content-Encoding other than identity, gzip, or deflate (including stacked encodings such as gzip, br) return HTTP 415 before body parsers run Limits: A proxy that decodes requests first needs its own mitigation; falls back to inflate: false, which also rejects gzip and deflate Still: Register the encoding guard middleware before every JSON, form, raw, text, and route-specific body parser https://patchtheplanet.org/brotli
- Team (workaround): covers Built-in image optimizer no longer fetches and decodes remote images when images.unoptimized is set globally Limits: Does not protect other server-side fetches, custom image loaders, or other Brotli decoders Still: Set images.unoptimized: true in next.config.js, rebuild and redeploy, and verify /_next/image no longer runs the optimizer https://patchtheplanet.org/brotli
- Team (workaround): covers Brotli decompressor filter disabled for request and response directions, so Brotli is not decoded at the gateway or sidecar Limits: A disabled filter passes encoded bytes onward, so downstream decoders stay exposed unless they reject Brotli; runtime_key overrides can re-enable it Still: Remove the Brotli decompressor filter or set both direction enabled defaults to false with no runtime_key, keep gzip and zstd filters, and verify the effective configuration on every gateway and sidecar https://patchtheplanet.org/brotli
- Team (workaround): covers Responses with Content-Encoding other than identity, gzip, or deflate are rejected before the body is read or decoded Limits: Applies only to the example request path; other HTTP clients need a raw-response mode or a Brotli-specific switch Still: Use preload_content=False and decode_content=False, check the Content-Encoding header, and only then read the body with decode_content=True https://patchtheplanet.org/brotli
- Cloudflare (waf-rule, since 2026-10-25): covers Requests proxied through Cloudflare Managed Ruleset covered by rule ...ca706f3c, which matches HTTP requests declaring Brotli request-body encoding (Content-Encoding: br), and rule ...402fe5bb, which matches requests to the Next.js image optimization endpoint /_next/image. Limits: Both rules default to the Log action, so matching requests are not blocked unless the customer changes the action; the Brotli rule does not match Accept-Encoding: br and no coverage is stated for non-proxied paths; blocking the Next.js rule may disrupt legitimate image optimization traffic. Still: Review existing ruleset-level Block overrides before deployment; switch the Brotli rule to Block if blocking is wanted, and change the Next.js rule to Block only if blocking is acceptable given image delivery impact. https://developers.cloudflare.com/changelog/post/2026-10-25-emergency-waf-release/

## Timeline

- 2026-10-23T21:57:31+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-111497
- 2026-10-23T22:49:07+00:00 analyst — Primary: Google CVE record/brotli releases v1.2.1/1.1.1/1.0.10 and Node.js Oct 21 advisory (rated high; CVE record CVSS4 9.2). Real-world exposure is mostly via Node.js, Python Brotli and Bun. No in-the-wild exploitation reported as of Oct 22-23. Aikido says a PoC appeared Oct 22 (first only against a weakened build, then reported RCE on unmodified Node 24.22.0, unreliable), but I could not find a primary link, so none is saved. OX Security warns against running unverified PoC/patch scripts. Python and Bun details come from Aikido and OpenSourceMalware, not from a PyPI or Bun primary page; Bun issue oven-sh/bun#46352 unread. Severity kept critical per the CVE record.
- 2026-10-24T00:12:39+00:00 lab https://patchtheplanet.org/brotli — OpenAI: Brotli vulnerability (CVE-2026-111497)
- 2026-10-24T03:31:37+00:00 github-poc https://github.com/mahumadad/CVE-2026-111497-assessment
- 2026-10-24T07:15:51+00:00 epss https://api.first.org/data/v1/epss?cve=CVE-2026-111497
- 2026-10-24T07:18:28+00:00 github-poc https://github.com/googlesky/CVE-2026-111497
- 2026-10-24T10:05:10+00:00 github-poc https://github.com/pt-act/node2shell-cve-2026-111497
- 2026-10-24T10:50:41+00:00 github-poc https://github.com/s1ko/poc-cve-2026-111497
- 2026-10-24T15:23:20+00:00 github-poc https://github.com/tc4dy/CVE-2026-111497-Toolkit
- 2026-10-24T22:31:28+00:00 github-poc https://github.com/mnk-works/cve-2026-111497-rce-checker
- 2026-10-24T23:16:44+00:00 github-poc https://github.com/syrex1013/CVE-2026-111497-node2shell
- 2026-10-25T01:12:28+00:00 lab https://developers.cloudflare.com/changelog/post/2026-10-25-emergency-waf-release/ — Cloudflare: WAF Release - 2026-10-25 - Emergency - Cloudflare Managed Ruleset · Changelog

## Documents

- [advisory] Node.js October 21, 2026 Security Releases https://nodejs.org/en/blog/vulnerability/october-2026-security-releases
- [advisory] CVE Record CVE-2026-111497 (Google CNA) https://www.cve.org/CVERecord?id=CVE-2026-111497
- [advisory] OpenAI: Brotli vulnerability (CVE-2026-111497) https://patchtheplanet.org/brotli
- [advisory] Cloudflare: WAF Release - 2026-10-25 - Emergency - Cloudflare Managed Ruleset · Changelog https://developers.cloudflare.com/changelog/post/2026-10-25-emergency-waf-release/
- [describes] Node2Shell: Node.js Brotli vulnerability allows remote code execution https://www.aikido.dev/blog/node2shell-nodejs-brotli-rce-cve-2026-111497
- [describes] Python Packages Vulnerable to Node2Shell https://opensourcemalware.com/blog/node2shell-affects-python
- [discussion] Node.js Brotli RCE (CVE-2026-111497) https://news.ycombinator.com/item?id=50189292
- [discussion] Node2Shell: Node.js Brotli vulnerability allows remote code execution https://news.ycombinator.com/item?id=50203180
- [discussion] Node.js security advisory: Brotli decoder RCE (CVE-2026-111497) https://news.ycombinator.com/item?id=50192733
- [discussion] https://x.com/AikidoSecurity/status/2113759110625906950 https://x.com/AikidoSecurity/status/2113759110625906950
- [discussion] Node2Shell: From Brotli Data to Remote Code Execution https://news.ycombinator.com/item?id=50204501
- [discussion] Node2Shell evolves to HTTP2Shell, blast radius affects many HTTP libs and apps https://news.ycombinator.com/item?id=50219177
- [discussion] @TheHackersNews: ‼️ Alert -  Critical Brotli flaw behind #Node2Shell RCE goes far beyond Node.js. https://x.com/TheHackersNews/status/2113916077923303786
- [discussion] Broccoli2Shell: Brotli decoder RCE (CVE-2026-111497) in Node.js, Python and more https://news.ycombinator.com/item?id=50221110
- [fix] google/brotli releases: v1.2.1, v1.1.1, v1.0.10 https://github.com/google/brotli/releases
- [mentions] Debian security tracker CVE-2026-111497 https://security-tracker.debian.org/tracker/CVE-2026-111497
- [mitigation] Vercel: Node.js security advisory, Brotli decoder RCE https://vercel.com/kb/bulletin/node-js-security-advisory
- [poc] mahumadad/CVE-2026-111497-assessment https://github.com/mahumadad/CVE-2026-111497-assessment
- [poc] googlesky/CVE-2026-111497 https://github.com/googlesky/CVE-2026-111497
- [poc] pt-act/node2shell-cve-2026-111497 https://github.com/pt-act/node2shell-cve-2026-111497
- [poc] s1ko/poc-cve-2026-111497 https://github.com/s1ko/poc-cve-2026-111497
- [poc] tc4dy/CVE-2026-111497-Toolkit https://github.com/tc4dy/CVE-2026-111497-Toolkit
- [poc] mnk-works/cve-2026-111497-rce-checker https://github.com/mnk-works/cve-2026-111497-rce-checker
- [poc] syrex1013/CVE-2026-111497-node2shell https://github.com/syrex1013/CVE-2026-111497-node2shell

## From the sources

Brotli vulnerability (CVE-2026-111497) — Patch the Planet

CVE-2026-111497 · Updated October 23, 2026

# Brotli decoder vulnerability

Crafted Brotli-compressed data can corrupt memory and allow remote code execution in affected software, including Node.js, Bun, and deployments of Envoy Proxy or Istio configured for Brotli decompression.

Fixes are available. Update affected deployments now. If you cannot patch immediately, disable Brotli decompression of untrusted data until the update is deployed.

## Start patching

Update to a listed fixed version or a later patched release in the same branch, then restart or redeploy.

Fixed releases · Reviewed October 23, 2026

| Project | Patch status | Fixed versions |
| --- | --- | --- |
| 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 Proxy | 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; 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. |

## Who is affected

Any application that passes attacker-controlled data to an affected Google Brotli decoder may be exposed. This includes compressed HTTP request bodies, responses fetched from untrusted servers, and compressed files. The bug can cause crashes, disclose memory, or allow code execution.

Check web services, background workers, tools that bundle Node.js or Bun, and deployments of Envoy Proxy or Istio configured to decompress Brotli.

Other software to check

- Embedded runtimes: apps such as Electron-based desktop tools can include multiple Brotli copies. Check both Chromium and Node.js; a fixed browser component does not establish that the embedded Node.js runtime is fixed.
- Native clients and bindings: check the decoder loaded by curl/libcurl, Python and Java bindings, and other native libraries. Bundled wheels and static binaries may need their own update or rebuild.
- File processing: include font decoders and data-file readers that use Brotli. Exposure is not limited to HTTP traffic.

Using Brotli only to compress outgoing data does not by itself establish exposure to this decoder flaw.

## Disable Brotli decoding until you can patch

You can keep other compression enabled. Disable Brotli decoding of untrusted data while allowing gzip, deflate, or other supported codecs. Apply this to every decoding path; if your stack cannot block Brotli separately, disable automatic decompression or pause that path until patched.

- Incoming requests: reject requests with `Content-Encoding: br` before any proxy, middleware, or body parser decompresses them. Cover direct-to-origin and alternate routes.
- Fetched responses: disable automatic Brotli decompression in HTTP clients. Reject Brotli responses before decoding; if your client cannot do this, pause the affected fetch or use a patched client. Removing `br` from `Accept-Encoding` alone does not stop a server from sending it.
- In Envoy Proxy and Istio, disable Brotli decompressor filters for both requests and responses. Disabling a filter can pass compressed data onward, so protect downstream decoders too.
- Files and other inputs: pause untrusted Brotli processing until the decoder is patched.

Turning off Brotli response compression on a CDN or web server does not disable request or client-side decompression. Request-size limits and WAF rules alone do not cover every decoding path.

Express: reject Brotli, keep gzip and deflate

Allow only uncompressed, gzip, or deflate request bodies before any parser runs. Keep automatic decompression enabled for those permitted encodings.

Express request encoding guard

Copy

```
// Register before every body parser or decompression middleware.
app.use((req, res, next) => {
  const encoding = (req.get('Content-Encoding') || 'identity')
    .trim().toLowerCase();

  if (!['identity', 'gzip', 'deflate'].includes(encoding)) {
    return res.status(415).send(
      'Use gzip, deflate, or an uncompressed request body.'
    );
  }
  next();
});

// Keep your existing parser options and register routes afterward.
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
```

Place this guard before all JSON, form, raw, text, and route-specific parsers. It rejects Brotli, unknown encodings, and stacked encodings such as `gzip, br` with HTTP 415. A proxy that decodes requests first needs its own mitigation.

If you cannot enforce the guard before decoding, set `inflate: false` on every existing body parser as a fallback. That rejects all compressed request bodies, including gzip and deflate.

Express body-parser options ↗

Next.js: disable built-in image optimization until Node.js is patched

If you cannot update Node.js immediately, set `images.unoptimized` globally. This stops the built-in image optimizer from fetching and decoding remote images. Merge this setting into your existing configuration, then rebuild and redeploy:

Next.js image optimization workaround

Copy

```
// next.config.js: retain your other settings.
module.exports = {
  images: {
    // Retain your existing images settings here.
    unoptimized: true,
  },
};
```

Images are served directly from their source URLs. Verify that requests to `/_next/image` no longer run the optimizer. This does not protect other server-side fetches, custom image loaders, or other Brotli decoders.

Next.js unoptimized image option ↗

Disable only the Brotli decompressor in Envoy Proxy and Istio

Remove the HTTP decompressor filter whose `decompressor_library` uses the Brotli type. Keep separate gzip and zstd decompressor filters. Alternatively, disable both directions in that existing Brotli filter:

Envoy Proxy Brotli decompressor settings

Copy

```
# Inside the existing Brotli decompressor's typed_config.
# Leave separate gzip / zstd decompressor filters enabled.
request_direction_config:
  common_config:
    enabled:
      default_value: false
response_direction_config:
  common_config:
    enabled:
      default_value: false
```

Replace the existing direction settings and remove any `runtime_key` from these two `enabled` fields; a runtime override can otherwise re-enable Brotli. An omitted direction defaults to enabled.

For Istio: edit the original `EnvoyFilter` patch that inserts the Brotli filter. Remove that insertion or apply the settings above to it. Do not remove every filter named `envoy.filters.http.decompressor`; gzip and zstd can share that name.

A disabled or removed filter passes encoded bytes onward. Reject Brotli before any remaining vulnerable application or client decoder. Verify the effective configuration on every affected gateway and sidecar, and test that permitted compression still works.

Envoy Proxy decompressor settings ↗ Envoy Proxy runtime flags ↗ Istio EnvoyFilter reference ↗

Python HTTP client: accept gzip and deflate, reject Brotli

With urllib3, leave the body unread and undecoded until you have checked its encoding. This example allows uncompressed, gzip, and deflate responses, and rejects Brotli even if the server ignores `Accept-Encoding`.

Python urllib3 response encoding guard

Copy

```
import urllib3

http = urllib3.PoolManager()
response = http.request(
    "GET", url,
    headers={"Accept-Encoding": "gzip, deflate"},
    preload_content=False,
    decode_content=False,
    redirect=False,
    retries=False,
    timeout=10.0,
)
try:
    encoding = response.headers.get("Content-Encoding", "identity")
    if encoding.strip().lower() not in {"identity", "gzip", "deflate"}:
        raise ValueError("Unsupported response content encoding")
    data = response.read(decode_content=True)
finally:
    response.close()
    response.release_conn()
```

Keep redirects and retries disabled for this example. If you add th

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
