Skip to content

8cd58bb0 - Pin Bun to 1.4.4 (Brotli CVE-2026-111497) - #526

Merged
TaprootFreak merged 2 commits into
21gifts:developfrom
Daniel-DFX:bun-1.4.4-runtime
Oct 29, 2026
Merged

TaprootFreak merged 2 commits into
21gifts:developfrom
Daniel-DFX:bun-1.4.4-runtime

Conversation

@Daniel-DFX

@Daniel-DFX Daniel-DFX commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

EN:
Pins every Docker stage to the exact oven/bun:1.4.4-alpine tag, because oven/bun:1.3-alpine is frozen on Bun 1.3.14 and a rebuild cannot pick up a fix.
Bun 1.4.4 updates its bundled Brotli from 1.2.0 to 1.2.1, which fixes CVE-2026-111497 (Brotli decoder out-of-bounds write); this service reaches that decoder through fetch to LNURL-pay hosts, which auto-inflates br responses.
CI setup-bun, engines.bun and the README, CONTRIBUTING and CONCEPT tables now say 1.4.4 as well.

DE:
Pinnt jede Docker-Stage auf den exakten Tag oven/bun:1.4.4-alpine, weil oven/bun:1.3-alpine auf Bun 1.3.14 eingefroren ist und ein Rebuild keinen Fix mehr bringt.
Bun 1.4.4 hebt das gebündelte Brotli von 1.2.0 auf 1.2.1 und behebt damit CVE-2026-111497 (Out-of-bounds-Write im Brotli-Decoder); dieser Service erreicht den Decoder über fetch zu LNURL-pay-Hosts, das br-Antworten automatisch entpackt.
CI-setup-bun, engines.bun und die Tabellen in README, CONTRIBUTING und CONCEPT nennen jetzt ebenfalls 1.4.4.

Details

Changes

  • Dockerfile: deps, builder and runtime stages use oven/bun:1.4.4-alpine (exact patch tag, so the image cannot silently stay on a vulnerable patch again).
  • .github/workflows/ci.yaml (both jobs) and .github/workflows/loan-e2e.yml: bun-version: 1.4.4 instead of latest, so CI tests the same runtime the image ships.
  • package.json: engines.bun >=1.3 → >=1.4.4. There is no packageManager field and no .bun-version file.
  • README.md, CONTRIBUTING.md, CONCEPT.md: Bun requirement ≥ 1.4.4.

Reused and added

Reused (only the version value changes):

  • Dockerfile:12, Dockerfile:19, Dockerfile:25: the existing three FROM stages.
  • .github/workflows/ci.yaml:26, .github/workflows/ci.yaml:59, .github/workflows/loan-e2e.yml:64: the existing oven-sh/setup-bun@v2 steps.
  • package.json:53: the existing engines.bun field.
  • README.md:63, CONTRIBUTING.md:18, CONCEPT.md:676: the existing version tables.

Added: nothing. No endpoint, control, error text, clock or permission check is added; no packageManager field or .bun-version file is introduced.

Verification (local, Bun 1.4.4 container + Postgres 16)

Step Result
bun install --frozen-lockfile pass, bun.lock unchanged (stays lockfileVersion: 1)
bun run lint pass (0 errors, 2 existing warnings)
bun run typecheck pass
bun run handbook:check / e2e:check pass
bun run test:coverage 191 files, 5682 tests pass, 100 % coverage (run as non-root; as root the two chmod-denial tests cannot fail a read)
bun run test:postgres 29 pass
bun run build pass
bun run e2e 709 pass
docker build . then docker run … bun --version 1.4.4 (revision 38afee6c84fcf48c0edb2466aa4b27d287a59c30)

Bun 1.4.0–1.4.4 release notes vs. this service

  • Brotli: 1.4.4 updates brotli v1.2.0 → v1.2.1 (Fix regressions since 1.4.3 in bun install, bunx, node:fs and node:http2, and update brotli oven-sh/bun#46392). The advisory lists 1.0.3–1.2.0 as affected and 1.2.1 as fixed. The 1.4.4 blog post itself does not name the CVE ID.
  • Bun.serve: port must now be an integer in range (1.4.0, else RangeError); index.ts passes the parsed BIND_ADDR port. Stricter Transfer-Encoding handling (400) and RFC 9112 Connection: close handling. idleTimeout: 0 semantics changed in 1.4.4; this service does not set idleTimeout.
  • SQL/postgres: connectionTimeout now bounds the whole handshake; PGSSLMODE=require against a non-TLS server now fails (1.4.0), so check that the deployed DATABASE_URL / PGSSLMODE matches the server. A swallowed error inside sql.begin() now rejects with ERR_POSTGRES_COMMIT_ROLLED_BACK (1.4.3); the two sql.begin call sites in index.ts do not swallow errors. Invalid bytea binds now throw TypeError (1.4.3). libpq URL parameters are no longer forwarded to the server (1.4.4). integration/sql-driver.test.ts already accepts both the 1.3 and 1.4 text[] binding behaviour and passes.
  • crypto: crypto.subtle became a prototype getter, HKDF keylen 0 now fails, and write() after digest() no longer throws. The service uses createHash().update().digest(), timingSafeEqual from node:crypto, crypto.subtle.importKey/AES-GCM, crypto.randomUUID() and crypto.getRandomValues(); none of these is affected by the listed changes, and the tests pass.
  • fetch: network errors reject with TypeError (1.4.0); a Content-Length mismatch now rejects, and chunked bodies are validated more strictly (1.4.3); non-ASCII header values are sent as Latin-1 (1.4.4). The LNURL-pay, price-candle and push fetches only send ASCII headers.
  • bun install: new lockfiles are v2 (v3 with overrides), but an existing v1 bun.lock is read with --frozen-lockfile unchanged.

Left out of scope

  • bun.lock still resolves the dev dependency @types/bun (and bun-types) to 1.3.14, so tsc checks against Bun 1.3 declarations. This is types only and does not affect the image or CI runtime; refreshing it is a separate lockfile change.
  • CONTRIBUTING.md (the postgres-text-array.ts tree entry and the Postgres test paragraph) says a JavaScript array cannot be bound by Bun SQL. Under Bun 1.4 it binds (see integration/sql-driver.test.ts:80-81); the literal form stays the project convention. This text predates this pull request.

oven/bun:1.3-alpine was last rebuilt on 2026-05-13 and is frozen on
Bun 1.3.14, which bundles a Brotli decoder affected by CVE-2026-111497.
Bun 1.4.4 updates Brotli to 1.2.1. All three Docker stages now use the
exact oven/bun:1.4.4-alpine tag, setup-bun installs 1.4.4 instead of
latest, and engines plus the README and CONTRIBUTING tables require
Bun >= 1.4.4.
@github-actions

Copy link
Copy Markdown
Contributor

EN:
Draft instructions
Thanks for your contribution! This repository follows the A38 quality rules.
Post the review record for this head from your own GitHub account and post the local CI report unless it is waived, as two separate comments in either order, and leave the pull request in draft. The local CI report starts the CI runs. Two review runs are required before the guard marks the pull request ready, once that CI and the required checks are green. One review is enough only when the pull request opener is listed in one_review_authors in the trusted .github/pr-guard.json on the default branch. A missing file, a missing key, or an empty list keeps two reviews required. An entry that exists only on the pull request head does not count.

DE:
Entwurf-Hinweise
Danke für deinen Beitrag! In diesem Repository gelten die A38-Qualitätsregeln.
Poste den Review-Nachweis für diesen Head von deinem eigenen GitHub-Konto und den lokalen CI-Bericht, sofern er nicht entfällt, als zwei getrennte Kommentare in beliebiger Reihenfolge, und lass den Pull Request im Draft. Der lokale CI-Bericht startet die CI-Läufe. Vor Ready sind zwei Review-Läufe erforderlich, sobald diese CI und die erforderlichen Checks grün sind. Ein Review reicht nur, wenn der PR-Eröffner in one_review_authors der vertrauenswürdigen .github/pr-guard.json auf dem Default-Branch steht. Fehlt die Datei, der Schlüssel, oder ist die Liste leer, bleiben zwei Reviews Pflicht. Ein Eintrag nur im PR-Head zählt nicht.

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

EN:
Approval required
This pull request needs an approval on the current head from someone with write, maintain, or admin who is not the author, so the guard can continue.

DE:
Freigabe nötig
Dieser Pull Request braucht auf dem aktuellen Head eine Freigabe von jemand mit Schreib-, Maintain- oder Admin-Recht, der nicht der Autor ist, damit der Guard die Arbeit fortsetzen kann.

Details
  • Changed paths: .github/workflows/ci.yaml
  • Changed paths: .github/workflows/loan-e2e.yml
  • An ordinary approving review on the current head is enough. No special review text is required. The reviewer needs write, maintain, or admin and must not be the author.
  • Geänderte Pfade: .github/workflows/ci.yaml
  • Geänderte Pfade: .github/workflows/loan-e2e.yml
  • Eine gewöhnliche freigebende Review auf dem aktuellen Head reicht. Kein besonderer Review-Text. Die Person braucht Schreib-, Maintain- oder Admin-Recht und darf nicht der Autor sein.

@Daniel-DFX

Copy link
Copy Markdown
Contributor Author

EN:
Local CI report
The A38 report below records the checks, results and durations.

DE:
Lokaler CI-Bericht
Der A38-Bericht unten dokumentiert die Prüfungen, Ergebnisse und Laufzeiten.

Details

Head: c1a15d4c1b906e195dd52bfa62aa91bae9943221
Recorded: 2026-10-28T15:01:12Z
Base: bafc82de513107c14e282f4bf83b5e622da5fde0
Policy: .github/a38.json at bafc82de513107c14e282f4bf83b5e622da5fde0
Changed paths: 6. Not every path ends in .md, so the local run is required.

Check / Prüfung Duration / Laufzeit Timeout / Zeitlimit Result / Ergebnis Exit code
lint: Lint 17 s 600 s pass 0

Durations and timeouts rounded up to whole seconds / Laufzeiten und Zeitlimits auf ganze Sekunden aufgerundet.

Original report / Originalbericht
{
  "base": "bafc82de513107c14e282f4bf83b5e622da5fde0",
  "changed_paths": {
    "all_markdown": false,
    "count": 6
  },
  "head": "c1a15d4c1b906e195dd52bfa62aa91bae9943221",
  "omitted": null,
  "policy": {
    "path": ".github/a38.json",
    "sha": "bafc82de513107c14e282f4bf83b5e622da5fde0"
  },
  "private": false,
  "recorded_at": "2026-10-28T15:01:12Z",
  "repo": "21gifts/api",
  "required": [
    "lint"
  ],
  "runs": [
    {
      "command": "agent a38 job commands --config '{\"env\":{\"CI\":\"true\"},\"steps\":[[\"bun\",\"install\",\"--frozen-lockfile\"],[\"bun\",\"run\",\"lint\"]]}'",
      "duration_s": 16.367883916944265,
      "exit_code": 0,
      "id": "lint",
      "name": "Lint",
      "result": "pass",
      "timeout_s": 600.0
    }
  ],
  "schema": "dfx-local-ci/v2"
}

The stack table in the canonical concept document still named Bun 1.3,
while the image, CI, engines and the other docs now require 1.4.4.
@Daniel-DFX

Copy link
Copy Markdown
Contributor Author

EN:
Local CI report
The A38 report below records the checks, results and durations.

DE:
Lokaler CI-Bericht
Der A38-Bericht unten dokumentiert die Prüfungen, Ergebnisse und Laufzeiten.

Details

Head: ff3d1d64c4db69121256c49c5a2647557788a28b
Recorded: 2026-10-28T15:05:14Z
Base: bafc82de513107c14e282f4bf83b5e622da5fde0
Policy: .github/a38.json at bafc82de513107c14e282f4bf83b5e622da5fde0
Changed paths: 7. Not every path ends in .md, so the local run is required.

Check / Prüfung Duration / Laufzeit Timeout / Zeitlimit Result / Ergebnis Exit code
lint: Lint 16 s 600 s pass 0

Durations and timeouts rounded up to whole seconds / Laufzeiten und Zeitlimits auf ganze Sekunden aufgerundet.

Original report / Originalbericht
{
  "base": "bafc82de513107c14e282f4bf83b5e622da5fde0",
  "changed_paths": {
    "all_markdown": false,
    "count": 7
  },
  "head": "ff3d1d64c4db69121256c49c5a2647557788a28b",
  "omitted": null,
  "policy": {
    "path": ".github/a38.json",
    "sha": "bafc82de513107c14e282f4bf83b5e622da5fde0"
  },
  "private": false,
  "recorded_at": "2026-10-28T15:05:14Z",
  "repo": "21gifts/api",
  "required": [
    "lint"
  ],
  "runs": [
    {
      "command": "agent a38 job commands --config '{\"env\":{\"CI\":\"true\"},\"steps\":[[\"bun\",\"install\",\"--frozen-lockfile\"],[\"bun\",\"run\",\"lint\"]]}'",
      "duration_s": 15.907667457999196,
      "exit_code": 0,
      "id": "lint",
      "name": "Lint",
      "result": "pass",
      "timeout_s": 600.0
    }
  ],
  "schema": "dfx-local-ci/v2"
}

@Daniel-DFX

Copy link
Copy Markdown
Contributor Author

EN:
First review with Grok 4.6
Ready after 2 review passes.
Pins the Docker image and CI to Bun 1.4.4, whose bundled Brotli fixes CVE-2026-111497.

DE:
Erster Review mit Grok 4.6
Bereit nach 2 Review-Durchläufen.
Pinnt Docker-Image und CI auf Bun 1.4.4, dessen gebündeltes Brotli CVE-2026-111497 behebt.

Details

Head: ff3d1d64c4db69121256c49c5a2647557788a28b
Runs: conformity-a with logic-a. Two reviews are required.
Lane conformity-a:
Provider: xAI
Model: Grok 4.6
Model number: grok-4.6
Result: pass
Prompt:

Read CONTRIBUTING.md and REVIEW.md at the base revision. Review this pull request against those files and against the linked issue. Do not change any files. Review the complete PR diff for conformity with CONTRIBUTING.md.

Lane logic-a:
Provider: xAI
Model: Grok 4.6
Model number: grok-4.6
Result: pass
Prompt:

Read CONTRIBUTING.md and REVIEW.md at the base revision. Review this pull request against those files and against the linked issue. Do not change any files. Review the complete PR diff for logical correctness.

Final result: passes 2, defects 0.
Set aside: none.

{"schema":"a38-review/v2","head":"ff3d1d64c4db69121256c49c5a2647557788a28b","passes":2,"defects":0,"set_aside":"none","lanes":[{"id":"conformity-a","result":"pass","status":"complete","provider":"xAI","model":"Grok 4.6","model_number":"grok-4.6","prompt":"Read CONTRIBUTING.md and REVIEW.md at the base revision. Review this pull request against those files and against the linked issue. Do not change any files. Review the complete PR diff for conformity with CONTRIBUTING.md."},{"id":"logic-a","result":"pass","status":"complete","provider":"xAI","model":"Grok 4.6","model_number":"grok-4.6","prompt":"Read CONTRIBUTING.md and REVIEW.md at the base revision. Review this pull request against those files and against the linked issue. Do not change any files. Review the complete PR diff for logical correctness."}]}

Fixed during review:

  • Pass 1, conformity: CONCEPT.md:676 still named Bun ≥ 1.3; fixed in ff3d1d64c4db69121256c49c5a2647557788a28b.
  • Pass 1, logic: no defects.
  • Pass 2: no defects in either lane.

@Daniel-DFX

Copy link
Copy Markdown
Contributor Author

EN:
Second review with GPT-5.6 Sol
There are defects that do not block the merge.

DE:
Zweiter Review mit GPT-5.6 Sol
Es gibt Mängel, die den Merge nicht blockieren.

Details

Pins the Docker image and CI to Bun 1.4.4, whose bundled Brotli fixes CVE-2026-111497.

Pinnt Docker-Image und CI auf Bun 1.4.4, dessen gebündeltes Brotli CVE-2026-111497 behebt.

Head: ff3d1d64c4db69121256c49c5a2647557788a28b
Runs: conformity-b with logic-b. Two reviews are required.
Lane conformity-b:
Provider: OpenAI
Model: GPT-5.6 Sol
Model number: gpt-5.6-sol
Result: pass
Prompt:

Read CONTRIBUTING.md and REVIEW.md at the base revision. Review this pull request against those files and against the linked issue. Do not change any files. Review the complete PR diff for conformity with CONTRIBUTING.md.

Lane logic-b:
Provider: OpenAI
Model: GPT-5.6 Sol
Model number: gpt-5.6-sol
Result: pass
Prompt:

Read CONTRIBUTING.md and REVIEW.md at the base revision. Review this pull request against those files and against the linked issue. Do not change any files. Review the complete PR diff for logical correctness.

Final result: passes 1, defects 3.
Set aside: none.

{"schema":"a38-review/v2","head":"ff3d1d64c4db69121256c49c5a2647557788a28b","passes":1,"defects":3,"set_aside":"none","blocks_merge":false,"lanes":[{"id":"conformity-b","result":"pass","status":"complete","provider":"OpenAI","model":"GPT-5.6 Sol","model_number":"gpt-5.6-sol","prompt":"Read CONTRIBUTING.md and REVIEW.md at the base revision. Review this pull request against those files and against the linked issue. Do not change any files. Review the complete PR diff for conformity with CONTRIBUTING.md."},{"id":"logic-b","result":"pass","status":"complete","provider":"OpenAI","model":"GPT-5.6 Sol","model_number":"gpt-5.6-sol","prompt":"Read CONTRIBUTING.md and REVIEW.md at the base revision. Review this pull request against those files and against the linked issue. Do not change any files. Review the complete PR diff for logical correctness."}]}

Defects, none of which blocks the merge:

  1. Low, conformity: bun.lock:235 and bun.lock:311 still resolve @types/bun / bun-types to 1.3.14, so the typecheck uses Bun 1.3 declarations. Types only; not changed here. The PR body now lists it under "Left out of scope".
  2. Low, conformity: CONTRIBUTING.md:111 and CONTRIBUTING.md:557 say Bun SQL cannot bind a JavaScript array, which is only true up to Bun 1.3 (integration/sql-driver.test.ts:80-81). Pre-existing text; listed under "Left out of scope" in the PR body.
  3. Low, logic: the PR body's crypto line left out timingSafeEqual, crypto.randomUUID() and crypto.getRandomValues(). Fixed in the PR body; no code change.

@TaprootFreak
TaprootFreak marked this pull request as ready for review October 29, 2026 16:55
@TaprootFreak
TaprootFreak merged commit c660bee into 21gifts:develop Oct 29, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants