Repository navigation
Security: patch the Brotli decoder RCE (CVE-2026-111497) in the backend and image builds - #82
Conversation
v1.2.7 ports google/brotli 0ed4268a. The block-switch fast path dropped decodeBlockTypeAndLength's result, so a crafted stream kept decoding with stale block state. The module reaches the binary through bogdanfinn/fhttp, which decodes `br` responses for the Genius lyrics client. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…li-libs Alpine builds nodejs with --shared-brotli, so the Filen helper's axios downloads decode `br` through the system brotli-libs. Alpine 3.20 is end of life and stuck on brotli-libs 1.1.0, which CVE-2026-111497 affects. Alpine 3.22 ships the 1.1.1 backport (with nodejs 22.23.4). The apk floor keeps an older brotli-libs from installing silently, and ffmpeg stays on the same 6.1 line. CI's Filen helper job moves to Node 22 to match the image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Node 20 is end of life and gets no Brotli fix. The build stage runs on the production host during `docker compose build`, so it moves to the patched 24.22.1, which matches the Node 24 line used in local dev. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 43 minutes. View limit details
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Node.js versions .github/workflows/ci.yml, backend/README.md, frontend/Dockerfile, mobile/tests/download-store.test.ts |
Backend Filen helper CI and its README now specify Node.js 22. The frontend build image uses Node 24.22.1. A mobile test comment states that mobile CI uses Node 20. |
Backend Alpine and Brotli versions backend/Dockerfile, backend/go.mod |
The backend runtime image changes to Alpine 3.22 and requires brotli-libs>=1.1.1. The indirect Go Brotli dependency changes to v1.2.7. |
Priority:
Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix
Merge Risk: 
Minimal · up to 73243
-
The reviewed version updates do not show an actionable merge-blocking risk.
Pre-merge checks: 
5
-
Full details: Docstring Coverage
-
Explanation
Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 1 files. (5 skipped: 5 unsupported.)
-
Finishing Touches
-
📝 Generate docstrings
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
I’m a rabbit; Node versions hop,
Backend CI moves to twenty-two.
Frontend builds on twenty-four,
Alpine and Brotli versions change.
I twitch my nose and cheer the update.
Comment @coderabbitai help to get the list of available commands.
The core, frontend and mobile CI jobs and the macOS release job still ran Node 20, which is end of life and gets no CVE-2026-111497 fix. The self-hosted Linux/Windows desktop build used an electron-builder image with Node 24.15.0. Every one of them runs `npm ci` or electron-builder downloads through Node's Brotli decoder, and the self-hosted build holds publish credentials. The jobs move to Node 22, and the builder image is re-pinned to today's `wine` build (Node 24.22.1; same Wine layers, with a refreshed Ubuntu base). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
setup-node uses whatever 22.x is in the runner's toolcache unless check-latest is set. Both the ubuntu-24.04 and macOS 26 images still carry 22.23.3, which predates the CVE-2026-111497 fix, so the major-only bump did not reach a patched Node. An exact pin matches how the workflows already pin go-version, and setup-node downloads it from actions/node-versions on a cache miss. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Why
CVE-2026-111497 (GHSA-9v8h-qqgm-4m35, the "node2shell" / "HTTP2Shell" bug) is an out-of-bounds write in the google/brotli decoder, versions 1.0.3 to 1.2.0. Google released 1.2.1, 1.1.1 and 1.0.10 on 21 Oct. The upstream fix is 0ed4268a: an invalid block switch was reported as
NEEDS_MORE_INPUTinstead of a format error. The streaming decoder therefore kept appending input bytes to its 8-byte internal buffer, guarded only by a debug-onlyBROTLI_DCHECK, and wrote past it. The fix addsBROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCHso the invalid switch becomes a permanent error. Any code that decodes abrbody from a party it doesn't control is exposed. That includes a client reading a response.What changed
andybalholm/brotliv1.2.0 (indirect, viabogdanfinn/fhttp, used by the Genius lyrics client)alpine:3.20(end of life): nodejs 20.15.1 linked against brotli-libs 1.1.0alpine:3.22(digest-pinned): nodejs 22.23.4 linked against brotli-libs 1.1.1.'brotli-libs>=1.1.1'fails the build rather than install an unpatched copy.node:20-alpine. Node 20 is end of life and gets no fix.node:24.22.1-alpine(digest-pinned), which includes the brotli cherry-pick. This stage runs on the production host duringdocker compose build."22"setup-nodepinned to22.23.4. A bare"22"takes the runner's cached 22.23.3, which predates the fix, becausecheck-latestis off. The pin also matches the new backend image's Node line for the Filen helper.scripts/build-desktop-docker.sh, self-hosted runner with publish credentials)electronuserland/builder:winefrom 2026-05-21, Node 24.15.0winebuild with Node 24.22.1. Its history differs only in a refreshed Ubuntu base layer, a Flatpak PPA key step and the Node version; the Wine layers are unchanged.Alpine builds nodejs with
--shared-brotli, so the backend image's exposure depended on the brotli-libs version, not the Node version. ffmpeg stays on the 6.1 line (6.1.1 → 6.1.2). Two comments that still said "Node 20" are updated.Not affected (checked)
requirements.txtat the pinned commit gives noBrotliorbrotlicffi. urllib3 and httpx only decodebrwhen one of those is installed.third_party/brotli. Electron's Node GN patch swapsdeps/brotlifor//third_party/brotli:dec/:enc. Chromium 150 vendors brotlicfa184a(2026-03-18), which contains 0ed4268a. So neithernet.fetchnor Node's zlib in the main process reaches a vulnerable decoder.process.versions.brotlistill reads 1.2.0 because cfa184a is a master snapshot taken after the fix but before the 1.2.1 release bumped the version macro.org.brotli:decdecoder (memory-safe). iOS decoding is in the OS.golangbuild stage, thenginxruntime andpostgresdon't decode Brotli request or response bodies.Verification
go build ./...,go vet ./internal/httpapi/...andgo test ./...pass. The DB-gated tests skip locally because noDATABASE_URLis set.apk addline in a bwrap sandbox on the sha256-checked Alpine 3.22.7 minirootfs:process.versions.brotli === "1.1.1", andlddshows/usr/lib/libbrotlidec.so.1.npm ci --omit=devsucceeds and the Filen helper's 19 tests pass on that Node.drawtextwith DejaVu work.npm run buildinfrontendpasses on Node 24. The edited mobile test file passes (29 tests).main, so this PR's CI won't build the images. The desktop builder image only runs inrelease.yml, so it gets exercised on the next desktop release.After merging
Production needs a manual rebuild on the host,
docker compose build backend frontend && docker compose up -d, becauseupalone reuses the old:localimages.🤖 Generated with Claude Code
Summary by CodeRabbit