Crafted Brotli data can run code on Node.js, Bun and Envoy

Researchers at OpenAI Codex Security found a memory-corruption bug in Google’s Brotli decoder. OpenAI says the bug lets an attacker run code with no account: a client can take over a server that accepts Brotli-compressed input, and a malicious server can take over a client that decodes its responses. Fixed releases for Node.js, Bun, Envoy, Istio and Brotli itself shipped under CVE-2026-111497, and Patch the Planet published the disclosure on October 23.
The Node.js advisory credits Khai Tran and Sylvie Mayer of OpenAI Codex Security with the report, and mcollina and aduh95 with the fix. OpenAI says it found the flaw during a red-teaming exercise. It is the second big disclosure this week from Patch the Planet, the OpenAI initiative that also published critical flaws in PHP.
A fix nobody shipped
OpenAI says Brotli’s source code already fixed the root cause in February. Nobody knew then that it was a security bug, and Brotli had cut no release since. Every program that bundled the library kept the vulnerable decoder for roughly eight months, until the new Brotli releases and the CVE came out.
That is how a library like this gets patched. “Since Brotli is built into other software, any software which includes this library needs to take the update too, followed by the users of that software,” OpenAI wrote. OpenAI says it disclosed the bug to Brotli and to downstream projects such as Node.js. Those projects have released security updates or are still releasing them, and Brotli published new versions and the CVE.
The bug is an out-of-bounds write: malformed compressed input makes the decoder write past the end of its buffer. The upstream patch, which Node.js copied in, makes the decoder detect the invalid input and stop sooner. Node.js bundles Google’s Brotli in its zlib module and runs it on every Brotli decode. That covers direct use of node:zlib and also plain fetch() calls, which decompress Brotli-encoded responses automatically.
Node.js shipped the fix on October 21 in coordinated security releases for the 22.x, 24.x and 26.x lines. Those releases fixed ten vulnerabilities, and four of them are rated high: the Brotli bug and three bugs in TLS and DNS hostname handling. Node.js 20.x and earlier are end of life and will not get the fix.
How bad is it in practice?
OpenAI calls it unauthenticated remote code execution and gives the client side a concrete example:
an unpatched client that accepts compressed input (such as “curl --compressed”) could be taken over by a malicious server.
Patch the Planet lists three possible outcomes: crashes, memory disclosure, or code execution. As The Hacker News reported, “remote code execution” is how the Node.js project describes what the flaw could allow, and Node.js rates it high, not critical. A public proof-of-concept appeared on October 22. It reached code execution only against a test build that had been weakened on purpose. On a standard Node.js build, its author reported a crash and a limited read of process memory. The outlet said no exploitation in the wild had been reported as of that day.
Who has to look
Patch the Planet’s test for exposure is whether attacker-controlled data reaches an affected Brotli decoder. Its examples are compressed HTTP request bodies, responses fetched from untrusted servers, and compressed files. Using Brotli only to compress your own outgoing data does not make you exposed to this decoder flaw. Turning off Brotli response compression on a CDN or web server also does nothing for request-side or client-side decompression.
The disclosure tells teams to check web services, background workers, tools that bundle Node.js or Bun, and Envoy or Istio proxies set up to decompress Brotli. It also names three places that are easy to miss:
- Embedded runtimes. Electron-based desktop apps can carry more than one copy of Brotli. Check Chromium and Node.js separately, because a patched browser component does not mean the embedded Node.js runtime is patched.
- Native clients and bindings. This covers the decoder that curl and libcurl load, Python and Java bindings, and other native libraries. Bundled wheels and static binaries may need their own update or a rebuild.
- File processing. Font decoders and data-file readers that use Brotli are in scope too, so exposure goes beyond HTTP traffic.
How you installed Node.js also matters. Debian and Ubuntu packages link against the system libbrotli, not the bundled copy, so on those systems the fix has to come through the distribution’s brotli package. As of October 21, the Debian security tracker had no open issue for brotli and no entry for this CVE. Official binaries, nvm, NodeSource and Docker images bundle their own copy and are fixed by the Node.js releases.
The fixed versions
Patch the Planet says to update to a listed fixed version, or to any later patched release on the same branch, and then restart or redeploy:
- Node.js: 22.23.4, 24.22.1, 26.12.1, on a supported release line.
- Bun: 1.4.4, which includes Brotli 1.2.1.
- Envoy: 1.40.0, 1.39.3, 1.38.6, 1.37.8. Version 1.36.12 also has the fix, but the 1.36 branch is unsupported.
- Istio: 1.29.9, 1.30.6, 1.31.2. The 1.29 line is end of life, so move to a supported one.
- Google Brotli upstream: 1.0.10, 1.1.1, 1.2.1. Pick the one that matches your library branch.
If you can’t patch today
The interim advice is to turn off Brotli decoding of untrusted data on every decoding path and leave gzip, deflate and other codecs running. If a stack can’t block Brotli on its own, disable automatic decompression or pause that path until it is patched. For incoming requests, reject Content-Encoding: br before any proxy, middleware or body parser decompresses the body, and cover direct-to-origin and alternate routes as well. Request-size limits and WAF rules alone don’t cover every decoding path.
For fetched responses, removing br from Accept-Encoding is not enough, because a server can send Brotli anyway. Patch the Planet says to switch off automatic Brotli decompression in the HTTP client and reject Brotli responses before decoding. If the client can’t do that, pause the fetch or move to a patched client. Its Python example uses urllib3 with preload_content=False and decode_content=False. The code checks the Content-Encoding header against identity, gzip and deflate and only then reads the body. Redirects and retries are turned off in the example, and any that you add need the same check on every response. With other clients, checking headers after a normal fetch() or an automatic body read can come too late.
The Express example is a middleware registered before every body parser. It accepts identity, gzip and deflate and returns HTTP 415 for everything else, including stacked encodings such as gzip, br. If the guard can’t run before decoding, the fallback is inflate: false on every body parser. That rejects all compressed request bodies, gzip and deflate included.
Next.js gets its own entry. If Node.js can’t be updated right away, set images.unoptimized: true globally in next.config.js, then rebuild and redeploy. This stops the built-in image optimizer from fetching and decoding remote images, and images are served straight from their source URLs. Patch the Planet says to check that requests to /_next/image no longer trigger the optimizer. The setting does not cover other server-side fetches, custom image loaders or other Brotli decoders.
On Envoy, remove the HTTP decompressor filter whose decompressor_library is the Brotli type. The alternative is to set enabled to false in both request_direction_config and response_direction_config of that filter. Two details there are easy to get wrong. A runtime_key left on those fields can turn Brotli back on, and a direction you leave out defaults to enabled. In Istio, edit the original EnvoyFilter patch that inserts the Brotli filter. Don’t delete every filter named envoy.filters.http.decompressor, because gzip and zstd filters can share that name. Once the filter is disabled, it passes compressed bytes downstream unchanged, so any vulnerable decoder behind it still has to reject Brotli.
Restart and verify
Updating the package is not enough on its own. Update runtime and image pins, and rebuild containers and executables that embed the affected runtime. Then restart or redeploy every service, worker, scheduled job and replica that still runs the old build. The final step in Patch the Planet’s guidance is to compare the running binary or image with the vendor’s fixed release, confirm that any temporary block rejects Brotli before decoding, and test that gzip and the other allowed codecs still work.
Up next
Grok Bot gets its own Vault for logins and cards, Video
Per a Threads post, Grok Bot got its own Vault for logins, contacts and credit card info, while its earlier 1Password route kept secrets inside the password manager. Where do your saved logins live right now, in a password manager or the browser?
Related stories
- OpenAI ships a Codex skill that checks sites for php2shell
- Cloudflare checks AI-found code flaws against live traffic
- OpenAI models helped find critical flaws in PHP
- libheif bugs reached OpenAI repos and GitHub Enterprise
- OpenAI agents tried a RubyGems bug found only in July
- Patch the kernel bug OpenAI’s agents turned into root
Comments
No comments yet. Be the first.
Join the conversation
Sign in to leave a comment. It appears after moderation.

