Repository navigation
Conversation
`comment.text = s` rejected `-->` only. The HTML tokenizer also ends a comment at `--!>`, and ends an empty comment at a leading `>` or `->`, so the rest of `s` left the comment and parsed as markup. Pin oven-sh/lol-html at ef9f6fd, a cherry-pick of upstream cloudflare/lol-html ba25359 (v3.0.0) onto the `bun` branch. `Comment::set_text` now returns `CommentClosingSequence` for all four forms.
|
Status: reproduced on bun 1.4.3-canary.1. |
|
Updated 8:32 AM PT - Sep 22nd, 2026
✅ @robobun, your commit 1678db9a664754e4efc62d9ff21ee341874b3236 passed in 🧪 To try this PR locally: bunx bun-pr 42646That installs a local version of the PR into your bun-42646 --bun |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: oven-sh/bun/.coderabbit.yaml Review profile: ASSERTIVE Plan: Essentials Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 5 remain after this review. WalkthroughThe PR updates the pinned Changeslol-html comment validation
Suggested reviewers: Priority: ➖ Normal 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
I reviewed this and didn't find any bugs. Because the actual behavioral change lives in the oven-sh/lol-html fork commit (a cherry-pick with two hand-resolved conflicts, and which also pulls in ea6125b), a human should eyeball that fork PR before landing — this diff only shows the pin and the tests.
What was reviewed:
LOLHTML_COMMITbump: constant name unchanged so.github/workflows/update-lolhtml.yml's sed still matches; no other occurrences of the old hash remain in the repo.- New
it.eachblocks inhtml-rewriter.test.js: the four rejected forms match the HTML tokenizer's comment-exit states (-->,--!>, leading>/->), the exact error message is asserted, and each accepted near-miss is round-tripped through a second parse to prove exactly one comment and no extra elements — the combined-object.toEqualand negative-contract check follow the repo's test conventions.
<details>
<summary>Extended reasoning...</summary>
Overview
The PR bumps the pinned oven-sh/lol-html fork commit in scripts/build/deps/lolhtml.ts from 725ce499… to ef9f6fd0… and adds a 33-line test block to test/js/workerd/html-rewriter.test.js. The fork commit is described as a cherry-pick of upstream cloudflare/lol-html@ ba25359 (a v3.0.0 security fix) onto the fork's v2.7.2-based bun branch, tightening Comment::set_text to reject --!> anywhere and a leading > or -> in addition to the already-rejected -->. The pin also picks up an unrelated fork commit (ea6125b for #41479) because the branch is linear.
Security risks
The change closes an HTML injection / XSS vector: before this bump, comment.text = "x--!><img onerror=…>" would let the <img> escape the comment. The direction is strictly tightening validation on user-controlled input, so the risk is not that the new check is unsafe but that (a) the cherry-pick onto the fork was resolved incorrectly (the PR notes two manual conflict resolutions in set_text and CHANGELOG.md), or (b) the pin picks up other unreviewed changes on the fork branch. Neither is visible in this repo's diff — the code that actually enforces the check lives in vendor/lolhtml and is fetched by commit hash at build time.
Level of scrutiny
Medium-high. The in-repo diff is trivial and the tests are well-constructed (parameterized, exact error message, accepted near-misses with a re-parse round-trip proving no element leaks, single combined .toEqual). But per the repo's dependency-bump guidance, a human should confirm the fork commit is merged to the bun branch (not an ephemeral PR head) and that the cherry-pick's conflict resolution in rewritable_units/tokens/comment.rs matches upstream's semantics — that review has to happen against oven-sh/lol-html#6, not this diff.
Other factors
No CODEOWNERS entries cover scripts/build/deps/ or test/js/workerd/. The old commit hash has no remaining references anywhere in the repo, and the LOLHTML_COMMIT constant name is unchanged so the update-lolhtml.yml workflow's sed pattern continues to match. The PR notes textual conflicts with #41479 and #41968 on the same line, which whoever merges second will need to re-pin. The test placement (existing html-rewriter.test.js, inside the existing "tagName, endTag.name, and comment.text setters" describe block) follows the repo's test-organization rules.
</details>
|
For the review of the fork side, these are the two things to look at. What the pin moves over.
How the cherry-pick differs from upstream.
The new check ( |
…rewriter-comment-closing-sequences
a4a3d0c is 725ce49 (the commit main pins) plus the cherry-pick of cloudflare/lol-html ba25359, and nothing else. The earlier pin ef9f6fd also carried ea6125b (linear-depth descendant matching), which is a separate change with its own cost.
|
The pin changed in 1678db9, and two statements in my earlier comment no longer hold.
Verified again with the new pin: |
There was a problem hiding this comment.
I reviewed the re-pinned version of this PR and found no bugs in the diff itself; because the behavior change lives in a fork commit outside this repo and the PR text no longer matches the code, a human should confirm the pin before merging.
What was reviewed:
scripts/build/deps/lolhtml.ts: the old725ce499pin has no other occurrences in the repo (grep), so nothing else needs updating;LOLHTML_UPSTREAM_BASEstays at v2.7.2, which is consistent with a cherry-pick rather than a rebase.- The PR description still says the pin is
ef9f6fd, but the diff pinsa4a3d0ce(per the latest commit message:725ce49+ cherry-pick of cloudflare/lol-htmlba25359only, withoutea6125b). I could not fetch the fork from this checkout, so whethera4a3d0cecontains exactly that is unverified here — worth a quick look at oven-sh/lol-html, and the description should be updated to match. html-rewriter.test.js: the new cases assert the exact new error message, and no existing test asserts the old(\-->`)wording. The accepted-list round-trip through a second parse checks the negative contract. The-->cases fail on the old pin only because of the reworded message; the--!>/>/->` cases are the real regression coverage.
Extended reasoning...
The diff is a one-line lol-html fork commit bump in scripts/build/deps/lolhtml.ts plus 19 new test cases in test/js/workerd/html-rewriter.test.js; no src/ code changes. It touches a security-relevant surface: HTMLRewriter comment.text previously let --!>, leading > and leading -> terminate the comment and inject markup, and the fix is a cherry-picked upstream security commit. Deferring rather than approving because the fixed code is in the vendored fork commit that is not in this checkout and could not be fetched here, the PR description names a different SHA (ef9f6fd) than the one pinned (a4a3d0ce), and the PR's own evidence block reports no local test run (deferred to CI).
|
Two answers for the reviewer of the pin. The description. It names What The |
|
A note on the pin here. oven-sh/lol-html#11 removes that cost (the map exists only while the open stack is deeper than 64) and keeps the pathological inputs linear. It is on the v3.0.1 line of the fork, which #43266 moves Bun to. #43266 also brings the If this PR is wanted on the v2.7.2 line instead, the one commit of oven-sh/lol-html#11 needs a backport onto |
Problem
comment.text = srejects-->only. The HTML tokenizer also ends a comment at--!>, and at a leading>or->. After one of these, the rest ofsis markup, for example a live<img onerror>.Comment::set_text(vendor/lolhtml/src/rewritable_units/tokens/comment.rs:70), which checks onlytext.contains("-->"). Its error:Comment text shouldn't contain comment closing sequence (`-->`).Upstream fixed it in cloudflare/lol-html@ba25359 (v3.0.0, a security fix).Fix
oven-sh/lol-htmlata4a3d0c: main's pin (725ce49) plus a cherry-pick of that commit, one commit in one file.Comment text shouldn't contain a comment-closing sequence.for all four forms. Near misses (--!,x--,a->b) stay accepted.test/js/workerd/html-rewriter.test.js(8 of 19 new cases fail on bun 1.4.3), the otherhtml-rewriter*suites,bundler_html.Background
HTMLRewriterbinds lol-html, built from theoven-sh/lol-htmlfork at the commit inscripts/build/deps/lolhtml.ts. A comment has no escape syntax, so the setter can only reject.bunbranch is now on v3.0.1 and has upstream'sba25359. If main moves there (HTMLRewriter: match nested and compound :not() selectors (lol-html v3.0.1) #43266), this fix comes with it, and only the tests here stay useful.Downsides
comment.text = "> quoted". An uncaught throw fails the rewrite.-->changed. Code that matches the old string no longer matches.comment.text =scans the text once more: 31 to 50 ns per call at 40 bytes (lol-html release build).Notes
Repro on bun 1.4.3-canary.1 (367d939). Main at bf80d21 pins the same lol-html commit.
With this PR all four throw.
Why four forms: after
<!--the tokenizer is in the comment start state.>there, or->(comment start dash state), emits an empty comment ("abrupt closing of empty comment"). Later,--moves to the comment end state, where>emits the comment and!moves to the comment end bang state, where>also emits it ("incorrectly closed comment"). Every other path appends to the comment data. lol-html's own parser follows the same states, which is what the second parse in the test shows.The two
-->cases in the new test fail on 1.4.3 only because upstream reworded the error. The other six fail because the setter does not throw.Pin history. The first version of this PR pinned
ef9f6fd, the same cherry-pick on top ofea6125b(linear-depth descendant matching, #41479), becauseea6125bwas the head of the fork'sbunbranch then. That commit slows selector matching on ordinary pages, which is #41479's trade to make, not this PR's. The fork'sbunbranch has since been rebased onto v3.0.1, so no v2.7.2-line commit can be on it. The pin is now main's own commit plus the one cherry-pick. It lives on the fork branchrobobun/comment-closing-sequences-v2.7.2. oven-sh/lol-html#6 (the PR against the oldbunhead) is closed, because the newbunalready has upstream's commit.The cherry-pick differs from upstream
ba25359in two places (git range-diff): theCHANGELOG.mdhunk is dropped (no v3.0.0 section on this line), andset_textkeeps the v2.7.2BytesCow::from_str_without_replacements(..)plusinto_owned(). lol-html checks ona4a3d0c:cargo test --features=integration_test170 + 3 + 32 + 2 pass.Cost numbers: a release build (LTO) of lol-html alone, 20,000 comments per document, Rust handler calls
set_texton each, median of 41 runs, three rounds, old and new alternated. Per call,set_textgoes from 30.9 to 49.6 ns (40 bytes), 82 to 114 ns (400 bytes), 2.13 to 2.25 us (4 KB). In Bun the JS handler call around it costs far more than either.This pin edits the same line of
lolhtml.tsas #41475, #41479, #41968 and #43266.no test proof · iteration 0 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/js/workerd/html-rewriter.test.js