Bye Bye Brotli? Google's Compression Library Is a Security Mess A memory-corruption vulnerability in Google's Brotli decoder, tracked as CVE-2026-111497 and dubbed HTTP2Shell, can be triggered by a maliciously crafted Brotli-encoded payload and affects web servers that decode Brotli on untrusted input. Google fixed the flaw in a commit on February 27, 2026, but did not treat the attacker-controlled input overrunning an eight-byte buffer as a security issue, and a new Brotli release did not ship until October 21, 2026, after Node's security advisory had already gone public. The author argues the incident, alongside a November 2025 Brotli memory-exhaustion denial-of-service issue fixed only by an undocumented new parameter, shows the compression library is in a state of disrepair. Bye Bye Brotli? Security https://www.bugsink.com/blog/tags/security/ Is it time to say goodbye to Brotli yet? My vote is on yes. This is where I’d love to same something smart about the vulnpocalypse, and how this is all super-relevant because of the new age of AI. I won’t, and instead will just say: the Brotli package is in such a state of disrepair that even mere humans would have been able to poke holes in it left and right. But first: some anime, so you know this is actually serious: This time So what got us here? It might have escaped your attention because the world was on fire over many security incidents e.g. PHP2Shell https://access.redhat.com/security/vulnerabilities/RHSB-2026-013 , eMudhra https://blog.google/security/protecting-chrome-and-android-users-from-compromised-emudhra-intermediate-ca-certificates/ , Railway https://blog.railway.com/p/security-disclosure-wednesday-october-21st and PingCAP’s breach https://www.pingcap.com/trust-hub/security/security-update-october-2026/ but we just had a thing called Node2Shell https://nodejs.org/en/blog/vulnerability/october-2026-security-releases . It’s now called HTTP2Shell https://www.aikido.dev/blog/python-packages-vulnerable-node2shell-brotli-cve-2026-111497 and I’d argue it should be called Brotli2Shell because that’s where the vulnerability actually is. What is it? It’s a memory-corruption vulnerability in the Brotli decoder that can be triggered by a maliciously crafted Brotli-encoded payload. Since brotli decoding is something that often happens with untrusted input, and in the case of web servers: sometimes even simply on any request, this is a very serious vulnerability. The timeline https://www.bugsink.com/blog/http2shell-timeline/ is somewhat sad though: Google fixed this in February 27, 2026 https://github.com/google/brotli/commit/0ed4268a4401abcb4472096340477cf4af7d1a2b , but apparently didn’t consider letting attacker-controlled input wander past the end of an eight-byte buffer into adjacent process memory a security issue. Since the regular release schedule for Brotli is “whenever the maintainer has time” it took until October 21, 2026 for a new release to be made. Also weird in the timeline: Node made their security advisory public before the Brotli release and puzzling what the consequences were for the rest of the world was left as an exercise to the broader public. The last time This wasn’t my first run-in with Brotli’s security “practices”. So I get to feel a bit more stupid than the rest of you. The previous time I ran into this was in November 2025. Bugsink got its regular dependabot warning https://github.com/bugsink/bugsink/pull/263 stating that it was running on an insecure version of Python Brotli, and that it needed to upgrade to a new version to be secure. The problem being fixed: because brotli compresses very well it’s possible to create “bombs”: small brotli files that expand in the failing scenario typically: in-memory to something very large and then cause a DOS via memory exhaustion. Bugsink accepts requests with a Content-Encoding: br brotli encoding, and automatically decodes those. Which meant that Bugsink was vulnerable to a trivial memory exhaustion DOS attack . However, upon reading the actual upgrade-notes I noticed that all the new version did was add a new parameter to a method , but that how this parameter was to be used was left as an excercise to the reader: there was no documentation for it, and the only other package that had figured out that something was to be done other than just upgrading, Scrapy https://github.com/scrapy/scrapy/pull/7134 , hadn’t actually figured out how to do that upgrade yet. Note: Upon researching this again in 2026 I noticed that this was flagged on the original PR too https://github.com/google/brotli/pull/1234 issuecomment-3744714019 . The lack of documentation bit actual implementers too. urllib3 implemented the new limit on 5 December 2025 https://github.com/urllib3/urllib3/commit/c19571de34c47de3a766541b041637ba5f716ed7 ; 153 days later it had to fix that implementation https://github.com/urllib3/urllib3/commit/2bdcc44d1e163fb5cc48a8662425e35e15adfe6a because it had introduced another high-severity decompression-bomb vulnerability https://github.com/urllib3/urllib3/security/advisories/GHSA-mf9v-mfxr-j63j . In other words: totally expected when you leave people to figure it out for themselves. Last time’s timeline The timeline for last year’s drama was also pretty bad: the fix was first committed in public view on Sep 17, 2024 https://github.com/google/brotli/pull/1201/changes/f1bdfaa803e62ce3608e0226c98da1cf20abebdc , merged on January 8, 2025 https://github.com/google/brotli/commit/67d78bc41db1a0d03f2e763497748f2f69946627 and the release notes, committed 9 days later https://github.com/google/brotli/commit/ad3c0d5f47e3dab8d199e8a8458660dcafa73606 , said: SECURITY python: added Decompressor::can accept more data method and optional output buffer limit argument Decompressor::process; that allows mitigation of unexpectedly large output; reported by Charles Chan It was then left unreleased until October 27, 2025 as version 1.2.0, 283 days after the release notes; the Python packages had to wait another 9 days until release. In brief, in days: - Day 0: Fix first committed in public view https://github.com/google/brotli/pull/1201/changes/f1bdfaa803e62ce3608e0226c98da1cf20abebdc - Day 113: Fix merged https://github.com/google/brotli/commit/67d78bc41db1a0d03f2e763497748f2f69946627 - Day 122: Release notes committed https://github.com/google/brotli/commit/ad3c0d5f47e3dab8d199e8a8458660dcafa73606 , with the literal words SECURITY ... mitigation of ... large output - Day 405: Tagged release of the C libraries https://github.com/google/brotli/releases/tag/v1.2.0 - Day 414: Python package released to PyPI https://pypi.org/project/Brotli/1.2.0/ - Day TBD: documentation on how to actually use this The next time I have very little confidence that this will be the last time we’ll have a severe security problem in this package. That’s obviously informed by the above, but also by the current state of the GitHub repository: Here’s 2 screenshots that should by themselves make the whole case: To make the slightly more explicit: that’s 3 out of bounds reads sitting in public view as PRs here https://github.com/google/brotli/pull/1593 , here https://github.com/google/brotli/pull/1594 and here https://github.com/google/brotli/pull/1595 , and a whole bunch of complaints about the release process missing release notes https://github.com/google/brotli/issues/1591 , when will the next release be released? https://github.com/google/brotli/issues/1540 , and a release tracker that is still open https://github.com/google/brotli/issues/1327 . Also: the maintainer says that resources are limited, and releases happen when he can find a slice of time https://github.com/google/brotli/issues/1540 issuecomment-6361140710 . Because it’s older in fact: over a year old the trivial CPU exhaustion for the .NET implemenation https://github.com/google/brotli/issues/1339 didn’t make that screenshot. Fun fact: because Google doesn’t publish this code as an official NuGet package this code is probably not widely deployed but I know it’s somewhat widely in-use by virtue of copy-pasta https://github.com/search?q=%2Fif%5Cs %5C%28len%5Cs %3D%3D%5Cs -1%5C%29%2F+%22Unexpected+end+of+input%22+path%3ABitReader.cs+language%3AC%23+NOT+repo%3Agoogle%2Fbrotli&type=code . So now what? So where are we now? My take on the above is: One of the world’s largest tech giants has been pushing a somewhat-specified new way to do compression with a reference implementation in C. While its support is basically limited to what one guy is able to do in his spare time. In other words: they’re not serious people , and we should act accordingly. For me Bugsink the way forward is not entirely clear, but there’s at least some things we can do. Not entirely clear because Bugsink is a Sentry-SDK compatible Error Tracker, and that means I’m aiming at accepting whatever Sentry SDKs send me. And since at least the Python sends Brotli-encoded messages, that means I’ll have to decode them. Still, I’m adding a feature to just turn this off https://github.com/bugsink/bugsink/pull/568 so that at least self-hosters that don’t actually use this sending-side can avoid future RCEs, and I’ve also asked upstream Sentry whether we can maybe just get rid of this https://github.com/getsentry/sentry-python/issues/8118 . There’s also the crazy idea of just vibe-coding a Python wrapper around a presumably more sane Rust implementation of Brotli https://github.com/bugsink/brotli-rs . Crazy idea, and I’m sure not ready to commit real code to it, but at least it’s there as an escape hatch now. For the rest of the world I’d say: maybe it’s time to seriously consider whether you actually need to support brotli in the first place . If nobody does, at least I get to say “I told you so”.