NewsLab
Oct 27 22:02 UTC

Broccoli2Shell: Brotli decoder RCE in Node.js, Python and more (broccoli2shell.com)

402 points|by theanonymousone||218 comments|Read full story on broccoli2shell.com
https://www.aikido.dev/blog/python-packages-vulnerable-node2...

Comments (218)

120 shown|More comments
  1. 1. est||context
    wtf Python is also effected. https://pypi.org/project/brotli/ not sure about shell
  2. 2. Incipient||context
    Side point from going to pypi:

    > Security notice: Upgrade certifi, pip, and uv in response to CA certificate incident

    Blimey PIP is affected? That's bad. I feel like that should have been bigger news?

  3. 3. murderfs||context
    Pretty sure that's the eMudhra "private key is 4" issue.
  4. 4. skeledrew||context
    Because pip uses it's own certificate bundle, so even if you fix the system itself pip still needs its own upgrade to handle the eMudhra episode.
  5. 5. tetha||context
    And strictly speaking you cannot trust the pip upgrade of pip with the vulnerable cert in the trust store due to certifi, which you also cannot upgrade safely with pip for the same reason. All of these are at one out of two compromises from being MITM'd during the upgrade.

    So strictly we have to burn everything python to the ground and reinstall entirely.

  6. 6. saltcured||context
    Heh. This is part of why I always preferred getting my python runtime and all these core libs from my linux distro packager. But python die-hards look at me like I'm insane when I suggest this.

    Even in today's LLM-addled world, I still think it's a better tradeoff for smaller system/site operators. Get the distro-level testing and regular auto-patching, rather than telling yourself it is a good idea to "freeze" your python world at the pace of your slowest app/system integrator.

    It's the same reason I think docker is an anti-pattern for these small groups. You really cannot safely use these strategies to bake an image and divorce yourself from the maintained distro layer unless you are going to adopt CI/CD that does the same thing. Keep tracking all these patches to the entire runtime with all the dependencies, rebuild, re-test, and redeploy.

    It's total cargo culting to adopt the freeze/image techniques and just abandon apps in place as if that is robust!

    But, it's also more than just automatically updating everything. There is an editorial aspect to distro management to help secure the supply chain to your app. Most smaller orgs cannot feasibly do this as well as the regular linux distro maintainers. Some large orgs can probably do it better, but that doesn't matter if you aren't doing it large org style with dedicated security folks tracking all this against well-developed policies and procedures...

  7. 7. graemep||context
    I agree about getting libs (binaries especially) from my distro, and it generally seems to be regarded as the "wrong thing to do". Freezing anything that might mean you get security updates slower seems to be a mistake to me.
  8. 8. zahlman||context
    > But python die-hards look at me like I'm insane when I suggest this.

    They have a point. The distro is only carrying a small fraction of what's available on PyPI, and will have out-of-date versions that may lack security patches (and for projects like yt-dlp, are highly unlikely to work at all). Realistically they aren't applying security backports; there would rarely be a reason not to just use the new version, and the resources just aren't there for that scale of patching anyway.

    Further, pip will interfere with your system package manager's tracking of the system environment (PEP 668), and any attempt you make to install from .deb/.rpm/etc. to a virtual environment is a hack at best. Maybe you could symlink individual package folders to the system environment while installing a superset, but ugh. Oh, and if you're a developer (like most "Python die-hards" are) then this isn't very helpful, as you aren't testing the installation of your package the way that your users will do it.

  9. 9. saltcured||context
    The mitigation is to ignore nearly all that stuff in PyPI, realizing it is barely a step up from copy-pasting out of stack overflow. Same goes for, e.g. python-whatever RPMs that look like they were drive-by contributions.

    So your trusted base is the Python runtime and maybe a few choice libraries that actually have engaged package management. Sadly, it is a trap to think you can put things on the internet as a small player by leveraging lots of third-party stuff, when you don't have the resources to actually maintain that large dependency base.

    This also may mean you want a base OS like Fedora and not some crusty "enterprise" variant that tries to bundle a frozen Python from 15 years ago. This is getting a little better in recent years, with some enterprise platforms having optional package streams for parallel install of newer runtime versions, etc.

    Edit to add: on the Fedora-derived platforms, pip doesn't really interfere much anymore. The platform python-* RPMs go into /usr/lib/... while pip installs into /usr/local/lib/... or your ~/.local/lib/... hierarchy. The only mysterious behavior you get is if you manage to install in both places and then you have to understand the path search order. Just like if you do strange things with user and virtual environments.

  10. 10. zbentley||context
    Eh, it's a personal choice and a not unreasonable position to take, but there are a lot of things on PyPi that aren't packaged by e.g. Debian. Database clients, immensely popular frameworks, scientific computing libraries ...

    Basically once you leave the realm of the 5-10 most popular building blocks in an area (which OS packagers do distribute), you're still left with plenty of packages that have 10ks+ of users, sane maintainer/security/ownership models, and code that would be very difficult to just copy-paste a la stackoverflow (e.g. native/compiled deps with complex wheel build tooling).

  11. 11. saltcured||context
    Yes, that's why I left wiggle room for a few choice packages you track yourself.

    What isn't really tenable for a small team is to drag in scores to hundreds of different third-party packages and rely on them all when you have no staff allocated to really evaluate and monitor so much upstream stuff.

  12. 12. aftbit||context
    Or - you can just upgrade pip with a SHA hash pin, or set the magic env vars to use the system bundle.

    You do need to be careful about creating new venvs with the old version of pip bundled in ensurepip in older Python releases. `uv` kindly patches that to newest pip, but not every Python binary does.

      python -m pip install "pip @ https://files.pythonhosted.org/packages/3f/06/3e4420302363fbb71be3c7f35ce042f54bfca330e3e66b3a2e3c4cca579f/pip-26.2.2-py3-none-any.whl#sha256=fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70"
    
    Or alternatively, on Debian with fixed system cert chain:

      PIP_USE_DEPRECATED=legacy-certs PIP_CERT=/etc/ssl/certs/ca-certificates.crt python -m pip install --upgrade "pip>=26.2.2"
    
    
    https://discuss.python.org/t/avoiding-compromised-certificat...
  13. 13. tetha||context
    Good to know. Does the first invocation recompute and check the hash of the wheel locally afterwards to ensure integrity?
  14. 14. aftbit||context
    Yep! I tested it with my own vibe-coded MITM proxy that hijacks pypi installations, which I created for ~$0.30 spend on DeepSeek API.

        $ python -m pip --no-cache install "pip @ https://files.pythonhosted.org/packages/3f/06/3e4420302363fbb71be3c7f35ce042f54bfca330e3e66b3a2e3c4cca579f/pip-26.2.2-py3-none-any.whl#sha256=fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70"
        Collecting pip @ https://files.pythonhosted.org/packages/3f/06/3e4420302363fbb71be3c7f35ce042f54bfca330e3e66b3a2e3c4cca579f/pip-26.2.2-py3-none-any.whl#sha256=fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70
          Downloading pip-26.2.2-py3-none-any.whl (1.8 MB)
             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 570.0 MB/s  0:00:00
        ERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. If you have updated the package versions, please update the hashes. Otherwise, examine the package contents carefully; someone may have tampered with them.
            pip @ https://files.pythonhosted.org/packages/3f/06/3e4420302363fbb71be3c7f35ce042f54bfca330e3e66b3a2e3c4cca579f/pip-26.2.2-py3-none-any.whl#sha256=fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70 from https://files.pythonhosted.org/packages/3f/06/3e4420302363fbb71be3c7f35ce042f54bfca330e3e66b3a2e3c4cca579f/pip-26.2.2-py3-none-any.whl#sha256=fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70:
                Expected sha256 fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70
                     Got        8c448177668e735cdde7d6178694b90c084ba18559348cc394c4b1546eeec89c
    
    
    
    The second one works too:

        $ PIP_USE_DEPRECATED=legacy-certs PIP_CERT=/etc/ssl/certs/ca-certificates.crt python -m pip install --no-cache --upgrade "pip>=26.2.2"
        WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1082)'))': /simple/pip/
        WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1082)'))': /simple/pip/
        WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1082)'))': /simple/pip/
        WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1082)'))': /simple/pip/
        WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1082)'))': /simple/pip/
        Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1082) - skipping
        ERROR: Could not find a version that satisfies the requirement pip>=26.2.2 (from versions: none)
        ERROR: No matching distribution found for pip>=26.2.2
    
    
    
    As compared with a naive installation through the proxy:

        $ python -m pip --no-cache install 'pip>=26.2.2'
        Collecting pip>=26.2.2
          Downloading pip-26.2.2-py3-none-any.whl.metadata (4.6 kB)
        Downloading pip-26.2.2-py3-none-any.whl (1.8 MB)
           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 775.3 MB/s  0:00:00
        Installing collected packages: pip
          Attempting uninstall: pip
            Found existing installation: pip 26.2.1
            Uninstalling pip-26.2.1:
              Successfully uninstalled pip-26.2.1
        Successfully installed pip-26.2.2
    
        $ cat venv/lib/python3.14/site-packages/sni_proxy_sentinel.txt
        SNI proxy lab sentinel. This file is inert.
  15. 15. tetha||context
    Oh nice. Then I have to thank you for a possible non-horrible upgrade path. If you were close by, I'd invite you for some icecream or a round of pool :)
  16. 16. aftbit||context
    It's safe to upgrade with python 3.12.16 now:

      # docker run --rm --net=host --add-host=pypi.org:127.0.0.1 --add-host=files.pythonhosted.org:127.0.0.1 python:3.12.16-slim-trixie pip install six
      WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate rejected (_ssl.c:1011)'))': /simple/six/
  17. 17. zahlman||context
    Yep. Per the main thread on the Python forums (https://discuss.python.org/t/information-for-python-users-re...), this now happens even with the outdated pip because the built-in `ssl` module has been patched to reject it. The relevant commit is https://github.com/python/cpython/commit/7dd8b4736a1419750b9... , featuring a rather amusing workaround for security scanners that might mistake the blacklisted certificates (included for testing purposes) for "leaked" certificates accidentally included in a source package.

    From code comments, because I found it interesting:

      * This is an extraordinary measure and last line of defense.  Removing trust is
      * primarily the job of the platform root store. This list only blocks keys while
      * that update is still propagating to the OS, container images, or root CAs
      * bundled in Python packages.  The threshold for adding an entry is very high.
      *
      * See https://github.com/python/cpython/issues/160040 for the eMudhra discussion.
    
    As a Mint 22.x user, I wonder if and when Debian or Ubuntu will pick up the change and release another patch for the system Python (basically, to my understanding, a base of 3.12.3 with security patches from other patch releases backported). Since they've already updated ca-certificates it might not seem necessary, at least as long as the pip package gets updated (although I don't use that anyway).

    BTW, I think I saw your comments in other places about the 30-cent vibe-coded MITM demo proxy, unless someone else had the same idea. Thanks for helping educate.

    Edit: apparently (https://discuss.python.org/t/avoiding-compromised-certificat...), the relevant Debian and Ubuntu packages already patch the distro-provided pip to enforce using the system certificates. (Indeed, `ca-certificates` is listed as "Depends" for the pip package, rather than "Recommends".) But maybe they'll still be interested in the key blocking, on defense-in-depth principles.

  18. 18. zahlman||context
    I had a pretty fun time with it myself. Rather than a system package for pip, or the `ensurepip`-provided one, I've been using the copy managed by pipx. I had to:

    * Update system certificates

    * Locate that pip and directly invoke it to self-update with hash pinning, rather than going through pipx

    * Fix a few stray venvs that contained their own pip

    * Use the fixed pipx to update uv (although I guess the uv self-update should work even for a pipx-installed copy?)

    The legacy-certs hint is neat. I did it the first way but would rather not have since I'm on Mint.

  19. 19. zahlman||context
    > All of these are at one out of two compromises from being MITM'd during the upgrade.

    This is not true; pip supports hash pinning, so an attacker would have to be able to defeat SHA256 as well (or compromise both the official Python discussion forum and PyPI itself, so as to forged the published hash). Other hashes can also be used. Instructions are provided on the Python discussion forum to self-upgrade pip with hash pinning: https://discuss.python.org/t/information-for-python-users-re...

  20. 20. steve1977||context
    Python certificate handling is a hot mess, even by Python standards.
  21. 21. zahlman||context
    Commentary like this adds nothing to the discussion and is simply provocative. Please don't.
  22. 22. steve1977||context
    Provocative of what? Thinking about the issues that Python has? Why would that be a problem?

    It IS a mess and it's causing problems again and again in real life. And it is particularly bad with Python. I don't see why this should not be pointed out.

  23. 23. zahlman||context
    ~~Recent versions of pip use `truststore` by default to access the system's certificates, only relying on the vendored `certifi` as a fallback or if explicitly directed.~~

    The above is incorrect per the Python forum discussion (https://discuss.python.org/t/information-for-python-users-re...). Pip will trust certificates from both sources.

    Users of uv who have already updated their system certificates can use:

      UV_SYSTEM_CERTS=true uv self update
  24. 24. tetha||context
    Well at least we know about it while or before the giant patch effort for everything else goes on. Just put it onto the pile.

    Who turned on hard mode this week?

  25. 25. loloquwowndueo||context
    Nah man. We were on casual mode all along. This is the new normal.
  26. 26. netsharc||context
    Well, whoever picked the name HTTP2Shell certainly didn't use any intelligence, artificial or genuine.

    It's so meaningless, broad and undescriptive of the actual issue. No it probably doesn't affect an HTTP server with nothing else behind it, so why is HTTP being blasted?

    You might as well call it Exploit Pro Max...

  27. 27. CharlieDigital||context
    Feels like the goal was sensationalism.
  28. 28. cromka||context
    Something that OpenAI would coin. Just like Anthropic did with Mythos.
  29. 29. reddozen||context
    The author clearly used super intelligence.
  30. 30. Stitch4223||context
    You and I, my friend, are the only ones in this thread not being sent to work in the glitter mines of south Arkansas as enemies of God's Country. SI has the best names, other intelligence is vastly inferior, using it is worse than many schisms of -isms combined.
  31. 31. techpression||context
    I immediately thought HTTP/2 was having a bad day somehow. Might I suggest Software2Shell to be less confusing.
  32. 32. CharlieDigital||context
    Specifically Brotli2Shell
  33. 33. photios||context
    google2shell would have been nice :D
  34. 34. anilakar||context
    Alt-tabbing from browser to terminal and back has always felt exhausting. Nice.
  35. 35. devsda||context
    With ad served malware, this wouldn't be the first time though :)
  36. 36. groundzeros2015||context
    All these names are silly. It's just marketing.
  37. 37. sigmarule||context
    There are levels of silliness, and this has achieved a new one.
  38. 38. cowlevel||context
    Actually it does, if the server is willing to decompress POST bodies.
  39. 39. croes||context
    Brotli bodies, so Brotli2Shell
  40. 40. SkiFire13||context
    And only those using Google's Brotli implementation.
  41. 41. jwilk||context
    What are the other implementations?
  42. 42. Rapzid||context
    I think we've all seen where an LLM names a session, issue, or PR based on its early understanding and fails update it later.

    AI isn't being asked to review the title, and it doesn't have experience or think, so of course it's not going to flag it.

    No human reviews anything anymore so of course they aren't going to catch it.

    Edit: AI for as good as it is at "writing" is terrible at writing and particularly at naming things. I had an AI name a client OpenAICompatibleEmbeddingClient. "Brooooo.. I think "compatible" is implied, who names stuff like that?!"

  43. 43. rmaxdev||context
    LLM-based AI is a synthesis of human observed behavior
  44. 44. PalmPilotProMax||context
    But does it bring synergy with our current paradigm?
  45. 45. lifeisloving||context
    Descriptive type names are a good thing. Id argue that one isnt that bad, but llms do take it to another level sometimes.
  46. 46. rafram||context
    That means that it supports other services with OpenAI-compatible embeddings APIs (not just OpenAI's own API). Seems reasonable!
  47. 47. Rapzid||context
    Fortunately I didn't ask it for excuses and so it didn't give them like a pedantic junior on the spectrum.

    Which they will happily do if you ask them "why" they did something. 100% they will give their best "well actually" impression.

  48. 48. ketzu||context
    `OpenAICompatible` is also a widely used phrasal description of a part/version of the OpenAI API that is supported by quite a lot of endpoints.

    - https://lmstudio.ai/docs/developer/openai-compat

    I've seen that used as a description for 2years or so.

  49. 49. rererereferred||context
    Just call it CVE-2026-111497. More accurate and much easier to remember and to talk about with your boss.
  50. 50. N19PEDL2||context
    Or EUVD-2026-108169.
  51. 51. kevincox||context
    I can maybe remember CVE-2026. But there is no way I can remember 6 random digits.
  52. 52. ygjb||context
    Yeah, because the six number chunk is near the limit of recall. Don't remember CVE-2026 since the year and CVE can be reconstructed from time memory. You know it came up this year. Remember that vuln 111-497 (as two chunks) came out this year, and remembering two short chunks is easier.
  53. 53. latexr||context
    I don’t know why you’d want to remember the number, but this one seems easy if you know some memory techniques.

    > Remember that vuln 111-497 (as two chunks)

    Good first step. Remember it’s two sets of three numbers. The first set is all ones, meaning the first three numbers are 1, then the fourth number is 4, then you add five for the next one (9), then you have to remember to subtract two (7)¹.

    May sound silly, but I bet some of you have already memorised it from that alone. Being a slightly convoluted by still logical set-by-step helps with recollection.

    ¹ Lot of different ways to go about that, like remembering that the first set was three of one so “two was left out”.

  54. 54. vanschelven||context
    Fun fact: not even Google can remember that number on the first try, apparently:

    https://github.com/google/brotli/issues/1597

  55. 55. TZubiri||context
    It looks like marketing HTTP2Shell seems to appeal to everyone that uses HTTP, while Brotli2Shell might not wake up people that know what it is.

    Now, whether it's warranted or not, that's another matter, but they know how to appeal for maximum awareness/interaction.

  56. 56. hulitu||context
    > while Brotli2Shell might not wake up people that know what it is.

    And, most of all, is damaging to Google, which are the master of software engineering. /s

  57. 57. super256||context
    A better name is Konduktsemmel, which is a bread roll (Semmel) which you eat on a funeral (Kondukt) in Austria. Fits to Brotli, doesn't it?

    (Actually you eat cake and drink coffee on a funeral, but it's still called like that in some parts of Austria.)

  58. 58. cowlevel||context
    A better name is Fred, because
  59. 59. vanschelven||context
    Should have definitely been Brotli2Shell, but Google ingeniously managed to dodge that bullet by having NodeJS come out with a fix before they did (others might call that accidental exposure), and then barely communicating about that with the broader community once they finally did. Here's a timeline of events[0] and here's me more broadly complaining about Google's stance[1]

    [0] https://www.bugsink.com/blog/http2shell-timeline/

    [1] https://news.ycombinator.com/item?id=50230362

  60. 60. francisduvivier||context
    Bro2Shell sounds better though
  61. 61. DaSHacka||context
    It will never not amuse me that Mozilla changed the Brotli extension to avoid this very connotation

    https://bugzilla.mozilla.org/show_bug.cgi?id=366559#c147

  62. 62. llm_nerd||context
    I mean...who cares? It's actually kind of strange that your comment got others talking about AI naming things.

    SQL Slammer didn't actually slam anything, and applied to a single vendor among many SQL providers. Heartbleed didn't make anyone's heart bleed...I mean, at least directly. Shellshock only impacted a single shell environment, again among many. Log4Shell impacted a single logging implementation, among many. Spectre and Meltdown...I mean, who would think that related to CPU cache side channels?

    These are just dumb names for people to share in referring to something. Seems silly and like a waste of time to spend effort getting upset about them.

  63. 63. davedx||context
    Honestly it's time to get rid of C as a language used where security is a factor. Enough already. Why the hell is a lib like brotli that processes public general internet traffic, and maintained by google, not in rust?
  64. 64. doublerabbit||context
    Because these applications were created long before Rust existed.

    There is a cost to conversion.

  65. 65. Gigachad||context
    Brotil was actually created post rust, but before rust took off.
  66. 66. davedx||context
    It's not even an application it's a compression library
  67. 67. _flux||context
    Rust-Brotli (by Dropbox) is actually a drop-in replacement for the Brotli C lib: https://github.com/dropbox/rust-brotli#:~:text=rust-brotli%2...

    Dropbox switched to it a decade ago, so it's probably quite product-ready.

  68. 68. anthk||context
    Check Librsvg, or php-rust. Or tons of gtk4-rs software doing it just fine.
  69. 69. thephyber||context
    Security is a factor everywhere. And C is everywhere. There's not going to be a "rewrite everything in Rust" project until after there is some legit penalty for selling / offering software in C that could be more secure in another language.

    I think Mozilla got it right when they abandoned the effort to rewrite the entire browser in Rust and instead focused on analysis of which modules needed priority rewrites. If a module has historically had zero memory-related bugs, then there are other higher priority things to spend time on.

    That said, Google Project Zero should have had Brotli on their radar. Hopefully they still have people and resources.

  70. 70. anthk||context
    Asterinax. RustPyhon. PHP 8.5 rewrite in Rust. FFMPEG and Qemu might follow soon. It's inevitable.
  71. 71. gsnedders||context
    I’ll point out that Servo was always a research project — any thought of it replacing Gecko was an incredibly long-term stretch goal. It was _a lot_ more interested in “can we write a high-performance browser engine in Rust” (there’s a reason why it significantly predates Rust 1.0 — they were very much developed together!) and “can we implement parallelism in places where browsers historically have not” (because you have more guarantees of safety).

    Chromium _has_ been replacing certain components with ones in safe languages, and it seems like that will continue slowly (with integrating them into the existing codebase, with web compatibility risk of any changes in behaviour, with the risk of performance and power regressions).

  72. 72. _flux||context
    I can understand why people used a C library for these apps, as when HTTP2 was specified, the C lib was the only game in down.

    However, why not switch to the Rust lib when it was available? I suppose people at Dropbox are now pretty happy they did in 2016: https://dropbox.tech/infrastructure/lossless-compression-wit...

    It's slower, though. Too high a price to pay for safety it seems.

  73. 73. uecker||context
    Sorry, I find the supply chain risks of Rust much more worrying than these memory safety issues. So how about we get rid of Rust? At least cargo is a problem.
  74. 74. nairboon||context
    Brotli2Shell seems to be a more appropriate name for this.
  75. 75. mkl||context
    Not when you're prioritising sensationalism over accuracy. Everyone's heard of HTTP, but hardly anyone's heard of brotli.
  76. 76. brazukadev||context
    call it GoogleBrotli2Shell then.
  77. 77. sli||context
    There's this other name for the same vuln: https://broccoli2shell.com/
  78. 78. cowsandmilk||context
    Article claims OpenAI found this in February, but I don’t think that’s correct. I think Google made a change to the Brotli source code in February that fixes the issue, but hadn’t realized it was a security issue and therefore hadn’t cut a release.
  79. 79. Rapzid||context
    Yeah that doesn't make a lot of sense that they reported it but also nobody knew it was a security issue..

    Maybe an LLM just happened to do one of those "while I'm here" fixes in Feb and because nobody reviews anything anymore..

    "Fixed reading too many bytes."

    LGTM!

    Edit: I was close! "Detect and report invalid stream earlier." Could have been a person.

  80. 80. zahlman||context
    > Could have been a person.

    The commit is attributed to "eustas" (Eugene Kliuchnikov) on the Google GitHub repo, who is the primary contributor to the Brotli project by a wide margin going back to 2015; so I think we can reasonably say it was.

  81. 81. serious_angel||context
    Thank you! Of course! I do believe these cases are dreams for LLM vendors to advertize themselves regardless truth, and many believe trends over actual evidence...

    Please do consider sharing the actual evidence to keep in the history, and respect actual human authors involved, their effort, time, and humane attitude... for discoveries, competition, actual achievements to learn from and get inspiration...

  82. 82. galadran||context
    Mozilla reported it as an RCE in April

    https://bugzilla.mozilla.org/show_bug.cgi?id=2029458

  83. 83. flyingjoe||context
    A few month ago, everyone was advising to use cool-downs in your package upgrades. Now we're constantly overriding those because security incidents will be exploited immediately. Guess that's just how it's gonna be from now on.
  84. 84. medler||context
    It used to be a flex to say you deploy daily but it’s going to become a necessity just to keep up with the vulns
  85. 85. ManuelKiessling||context
    CI/CD — Continuous Incidents, Continuous Defense.
  86. 86. mort96||context
    Yeah, obviously? Deploy fixes to security issues which apply to you as soon as possible, deploy random feature additions and non-critical bug fixes after some cooldown.

    As always, the easiest way to manage this is to have as few dependencies as possible. If you have a lockfile with thousands of entries, you won't be able to go through them and decide which upgrades are legitimate urgent security updates and which can wait. If you have 10? You'll manage.

  87. 87. da_chicken||context
    Exactly.

    Security fixes for actively exploited vulnerabilities demand an emergency response. The risk of introducing new, unknown flaws is less than risk of having an active known exploited vulnerability.

    However, absent the risk of a KEV, that changes the equation. Now the risks of code changes causing breaking changes plus the risk of supply chain attacks is greater than the risk of having to put some thought and time in to manage your software library versions.

    It's not like AI created this distinction, either. Neither did CI/CD. This is standard systems administration -- literally ISO/IEC 20000 ITSM. It's exactly why, traditionally, new features are often limited to major versions. It's why binary compatibility was a huge issue with RHES 20 years ago, and why distros pin versions and backport security and selective bug fixes. A developer that doesn't know this is telling on themselves why they shouldn't have write access to production. Stability matters a lot because we like to get paychecks.

  88. 88. acdha||context
    That's why it's important to practice your processes for both shipping quickly and overriding cooldowns. There's a baseline of things which are not easy to exploit where you want to patch on a regular cadence and the risk posed by a supply chain attack is greater than the risk of an attacker having enough of a footprint inside your systems to escalate. The fact that sometimes you have a specific situation like this where that's not true doesn't mean that 9 times out of 10 the cooldown was the better risk-reduction strategy.
  89. 89. gsnedders||context
    A cooldown is a coarse way to deal with “supply chain security” — and that’s mostly a question of how much you trust your dependencies.

    You may well (and probably should) trust the maintainers and release process of Brotli, Node.js, PHP, etc. security releases more than you trust some-random-JS package deep in your front end dependency graph.

    You want to reduce the risk of introducing a compromised dependency into your product, and that’s largely a question of how much you trust upstream.

  90. 90. upofadown||context
    An example of the cost of added complexity I suppose. Brotli is much more complicated than the gzip/deflate it replaces. ... and of course we still have to expose gzip to attack as well.

    Every time you add something you lose something...

  91. 91. TacticalCoder||context
    I really don't understand how so many different things are affected by the same brotli bug/exploit.

    I even read the patch for the C code (patch which, btw, seems a bit hacky to me with isSafe? methods added and whatnots but YMMV: now I understand things had to be patched in a hurry but this patch really looks like "lipstick on a buffer overflowing C pig" to me).

    What's the link between Python / Node / C++ / libbrotli / Envoy / Bun: are those some all using the same C brotli encoder/decoder?

    Can someone who knows more explain why all those are vulnerable?

    > As for unaffected software, Apache’s standard mod_brotli does not decode Brotli

    Because this one only encodes and doesn't decode and the bug is in the decoder? (for I take it mod_brotli, with such a name, still does something brotli related and isn't, say, a TOTP token generator nor a SAT solver?).

    I mean overall, sheesh: could we get better explanation / better writeups when such big fuckups happen?

  92. 92. Rapzid||context
    Yes. All these language runtimes compile against common libraries. Compression libs are one of the most common common libraries that platforms like node, ruby, dotnet, python, and etc need to compile.

    Google provides the Brotli implementation. Package maintainers slurp that up and create ie libbrotli-dev. When you compile node it uses that for brotli support.

  93. 93. thephyber||context
    Brotli was a library released by the Google team that developed it. There weren't lots of independent implementations; they were all from the same source code.
  94. 94. rfgplk||context
    Or you can roll your own and not rely on the literal disaster that Google developed. Brotli is trivial to implement.
  95. 95. thephyber||context
    Well did you?

    Your comment is irrelevant to mine. I stated what is, while you stated what ought to be.

    It's trivial to make any open source repo that nobody uses. It's hard to get people to adopt your library over one supported by one of the world's largest companies.

  96. 96. Rapzid||context
    > reported it as unauthenticated remote code execution that works in both directions

    > but it wasn't recognized as a security issue at the time and no release shipped with the fix until now

    I'm always getting my dangerous RCE bugs mixed up with my harmless RCE bugs.

    I'm curious how this was reported and fixed back in Feb but nobody recognized the importance. A case of AI automation and nobody at the wheel?

  97. 97. wavemode||context
    I'm not seeing any source for the claim that OpenAI discovered this in February. The source that the article links (a tweet by OpenAI) doesn't claim that.
  98. 98. soiax||context
    Exatly, it was patched silently, OpenaAI just discovered that patch, and that it has upstream effects in NodeJS etc.
  99. 99. zahlman||context
    No matter who discovered it, there was a patch in late February. One can excuse them for describing the commit as something ordinary to avoid alerting the baddies (traditional "disclosure window" etc. stuff) but it's absurd to me that the corresponding releases, with no other code changes (per the commit history), took almost 8 months.
  100. 100. galadran||context
    Mozilla found and reported it as an RCE in April: https://bugzilla.mozilla.org/show_bug.cgi?id=2029458
  101. 101. zahlman||context
    [Edit: I was inattentive and replied twice in different ways, thinking they were to different parent comments; I've now merged my thoughts and edited them to be more coherent.]

    > reported

    This is Mozilla's own discussion of the issue, though. There's mention of

    > https://github.com/google/brotli/blob/master/SECURITY.md suggests that it should go through Google's regular vulnerability reporting process. I don't have any more specific knowledge around this library, however.

    but that doesn't establish that this was done.

    If it was done, then I think we deserve answers about why it took Google almost 8 months to release a new version of a common dependency, applying a security patch (and no other changes!) when the vulnerability was known at least 6 months ago (and possibly the full 8 months ago) to cause RCE.

    If I'm understanding the report correctly, the patch was applied in Firefox's vendored copy within days, and available in 151 and I guess some 150.0.x release. And also they were supposedly beaten to the punch:

    > Probably we should update to cfa184a997ac19454d5a3ae97f6d600aac2445a6 which was rolled into chromium 2 weeks ago. If there are other recent sec fixes this would pick them up

    It seems even more embarrassing if chromium got the patch but Chrome didn't. And if Chrome did, then it's that much more appalling not to see a patched separate release for so long.

    (I was confused trying to go through the technical details, though: the "affected code" seems to have very little overlap with the code actually altered by the patch.)

  102. 102. zahlman||context
    Just as a follow-up: elsewhere in (or at least via) the thread I found user vanschelven's write-ups

    https://www.bugsink.com/blog/http2shell-timeline/

    https://www.bugsink.com/blog/bye-bye-brotli/

    and they cover the timeline better than I do.

  103. 103. bawolff||context
    To me, the surprising part is how many of these implement brotli compression of request (not just response) bodies, given how obscure a feature that is.

    In any case all this sensationalism is starting to get annoying. Patch your stuff and move on.

    Edit: actually, between all the sensationalism, its hard to tell from the article how many of these actually support brotli compressed request bodies in common configs vs some other use of brotli (which is bad but nowhere near as critical)

  104. 104. ArcHound||context
    I think the issue is that the servers "silently" support brotli. Then nobody uses it, but the attacker can still abuse the feature.

    So as a hotfix I block this on my reverse proxy.

  105. 105. bawolff||context
    But is that actually true?

    It seems like node supports it with body parser enabled.

    But im having trouble finding any docs suggesting anything else supports it on inbound requests.

    Obviously there are other scenarios where it is exploitable, but it is a much less severe vuln if the attacker must first force the program to make an outbound request to a server of its chosing rather than just connect to a vulnerable server.

  106. 106. Rapzid||context
    Asp.Net adds Brotli support if you "UseRequestDecompression" or "UseResponseCompression".

    DotNet, however, has it's own C# Brotli implementation.

  107. 107. ArcHound||context
    The idea is to identify brotli encoding in the content-encoding header and block that on nginx. This shouldn't reach vulnerable brotli parser in node.

    I hope my assets are not connecting to malicious servers, otherwise yes, I have a problem.

  108. 108. dboreham||context
    According to Claude when I asked it to audit one of our Python applications, there are scenarios where Brolti can be used only when some Python library detects that the C library is installed on the system. So your Brolti-ness can depend on which machine your code runs on. Ymmv, it didn't look to be a practical possibility in our code so I didn't probe further.
  109. 109. mort96||context
    These chat bots always hedge like that. They will never give you a straight answer, it's always "depending on version and build configuration and system configuration".

    Investigate yourself. Read the documentation. Grep for brotli in the source. Don't blindly trust a chat bot when it says it "might happen in certain configurations".

  110. 110. dboreham||context
    Chat bot lol. It did all of those things including scanning the binary. I ran it after doing my own (albeit more limited, but maximal-human) investigation.
  111. 111. mort96||context
    Is that meant to be a response to what I wrote or did you reply to the wrong comment
  112. 112. DaSHacka||context
    I've noticed the newer frontier models are a lot better about this and are willing to give concrete answers, where before even in 90/10 scenarios they would always be wishy-washy espousing the "it depends on the circumstances" BS.
  113. 113. bscphil||context
    The only reply to this criticizes the hedging, but I think it's actually true and it does make it harder to tell if you're vulnerable to this. And on top of that, quite a few systems have brotli installed by necessity. On Debian 12, for example, I have the following dependency chain on a VPS I run:

    grub-pc -> grub-common -> libfreetype6 -> libbrotli1

    which is really nasty.

  114. 114. bflesch||context
    Cloudflare has this amazing feature where it accepts compressed payloads and forwards them to unsuspecting backends. Can be weaponized in many ways.
  115. 115. AlienRobot||context
    I wonder if we'll see more of this thanks to AI. Extremely complex features that nobody uses and that were easy to add, which incidentally tremendously expand the attack surface. One would hope that maintainer would be wise to avoid that, but for how long?
  116. 116. ArcHound||context
    I think so, especially vibe coded software. I think hackers have the advantage now and defenders need to limit attack surface more rigorously.

    Unfortunately that means understanding and limiting dependencies of developers... Yea, good luck.

    My popcorn is ready. My servers are not.

  117. 117. whoanoway||context
    I'm not saying that my experience translates 1:1. As a child of domestic violence, all I can say is that it never gets better. Sadly, my feeling is that the violence will only escalate from here. If you look at the bright side, you can earn your stripes as a legitimate infosec engineer and prove your worth to the industry and the world.
  118. 118. ArcHound||context
    I'm sorry that happened to you. I tend to agree that the race to the bottom will continue.

    And don't worry about my stripes, I'm mostly talking about my hobby self-hosted apps. If anything, should someone hack them I'll have a funny article to post on my blog. Professionally, I do things differently.

  119. 119. fock||context
    https://github.com/tmux/tmux/pull/5709/changes it is already happening. Nice 50 lines of C-code to add support for kernel-keyrings which no userland software uses and literally is a one-line config-option.
  120. 120. therein||context
    My experience with Brotli is from back when all the hype was mobile first and India etc was super mobile first so all these social networks lost their mind optimizing for request success and speed. So they were going crazy over micro-wins like that.