Skip to content

test: pin html escaping of clipboard link labels - #1166

Merged
kalvinnchau merged 1 commit into
mainfrom
cid/clipboard-html-alerts
Oct 15, 2026
Merged

kalvinnchau merged 1 commit into
mainfrom
cid/clipboard-html-alerts

Conversation

@kalvinnchau

Copy link
Copy Markdown
Contributor

Summary

Adds a regression test pinning HTML escaping of DOM-derived link labels in the message selection serializer (src/features/messages/selection-copy.ts). No production code changes.

The test feeds "><img src=x onerror=alert(1)> through each label source that can carry markup — a mention's data-mention-name, a nameless chip's text, and a link's data-link-label — and asserts the exact text, Markdown and HTML output. The Markdown result goes through the serializer's own HTML read-back, so it also proves the payload stays text. Removing <>" escaping from labels while keeping & escaping was caught only by this test.

Code-scanning disposition

These js/xss-through-dom alerts are false positives:
alert 24,
alert 25,
alert 26,
alert 27,
alert 28,
alert 29,
alert 33.

  • Every reported flow leaves link() through its Markdown or plain-text return. None passes the format === "html" return, so CodeQL already recognizes escapeHtml there.
  • All of the sinks parse serializeNode(..., "html") output. That format propagates unchanged through serialize/children and always selects the escaped return.
  • CodeQL is path-insensitive on the format argument, so it can't tell that the other two returns never reach the sinks.
  • In the HTML path, every DOM-derived value (text, emoji alt, link href and label, code language) is escaped. Tag names come from fixed sets, the list start is numeric, and destinations are gated by profileKey, parseBuzzLink and safeLinkUrl.

Alert 25 is in production code. The others are test read-backs in selection-copy.test.tsx and EditableInput.test.tsx. The alerts remain open until dismissed; this PR does not change their state.

Verification

  • pnpm check: pass.
  • vitest run src/features/messages/selection-copy.test.tsx src/features/messages/EditableInput.test.tsx: 235/235 pass.
  • Mutation check: dropping escapeHtml(label) from link() fails the new test (HTML mismatch, and the Markdown read-back loses the label to a parsed <img>).
  • Pre-push jobs (scripts/check-push.mjs, plus --design and --clippy): pass.
  • Full vitest run locally: 6 failures (4 timeouts, 2 UI-query misses) in App.profile, ChannelMembersDialog and InboxPage under heavy machine load. Those three files pass 157/157 when run alone. Deferred to CI.
  • No browser journeys added or removed.

🤖 Generated with Claude Code

mention names, nameless chip text and link labels are read from the dom and
escaped by the html serializer before the markdown path parses them back.
pin that contract for each label source so an escaping regression fails
the html and markdown round trip.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Kalvin Chau <[email protected]>
@kalvinnchau
kalvinnchau requested a review from a team as a code owner October 15, 2026 03:14

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Carl, an automated reviewer, commenting via Wes's GitHub account.

No blockers. The exact text/Markdown/HTML expectation covers all three label sources (mention attribute, nameless chip text, data-link-label). Local mutation check: dropping escapeHtml(label) in selection-copy.ts link() fails this test. Merges cleanly alongside #1162, which touches messageHtml (no-op there, single &).

@kalvinnchau
kalvinnchau merged commit 8857525 into main Oct 15, 2026
32 checks passed
@kalvinnchau
kalvinnchau deleted the cid/clipboard-html-alerts branch October 15, 2026 15:28
johnmatthewtennant added a commit that referenced this pull request Oct 15, 2026
* origin/main:
  perf(css): replace wide :has() anchors with owner-set data attributes (#1180)
  fix(goose): share an MCP server pool and harden session lifecycle (#1142)
  test(browser): hold reading focus until the unread baseline is observed (#1182)
  Refine the profile menu and open status editing immediately (#1172)
  unify session naming, workspace and lifetime settings (#1079)
  perf(messages): stop forcing a layout on every action bar position frame (#1184)
  test(browser): prepare fixture dependencies once per run (#1126)
  test: replace fragile string assertions with precise checks (#1162)
  test: keep thread fixture errors out of http responses (#1163)
  feat: upgrade tauri and native plugins (#1169)
  test: pass native menu scripts to eval as arguments (#1160)
  test: cover shared link url policy (#1165)
  test: preserve literal text across markdown comment projection (#1164)
  test: pin html escaping of clipboard link labels (#1166)
  Preserve linked text pasted from other apps (#1069)
  fix(messages): keep the reader's message in place when a thread reply and layout change land together (#1130)

Signed-off-by: John Tennant <[email protected]>

# Conflicts:
#	src/bundled/channels/ChannelBody.tsx
#	src/bundled/channels/ConversationTab.tsx
johnmatthewtennant pushed a commit that referenced this pull request Oct 15, 2026
* commit 'f2595b8df20c9e6e91f79e77b52b700137063a49': (25 commits)
  Add community leave and device removal settings (#954)
  perf(css): replace wide :has() anchors with owner-set data attributes (#1180)
  fix(goose): share an MCP server pool and harden session lifecycle (#1142)
  test(browser): hold reading focus until the unread baseline is observed (#1182)
  Refine the profile menu and open status editing immediately (#1172)
  unify session naming, workspace and lifetime settings (#1079)
  perf(messages): stop forcing a layout on every action bar position frame (#1184)
  test(browser): prepare fixture dependencies once per run (#1126)
  test: replace fragile string assertions with precise checks (#1162)
  test: keep thread fixture errors out of http responses (#1163)
  feat: upgrade tauri and native plugins (#1169)
  test: pass native menu scripts to eval as arguments (#1160)
  test: cover shared link url policy (#1165)
  test: preserve literal text across markdown comment projection (#1164)
  test: pin html escaping of clipboard link labels (#1166)
  Preserve linked text pasted from other apps (#1069)
  fix(messages): keep the reader's message in place when a thread reply and layout change land together (#1130)
  separate session sharing from explicit channel conversion (#1070)
  feat(goose): bundle goose-acp with the app (#1110)
  feat(agents): answer unmentioned messages in one-to-one DMs (#1173)
  ...

Signed-off-by: Sol <49aa1f65411fd096d2e2ec144f1e7aa36fdc76d1b907cfdf7be000c66f9d3b8e@buzz.block.builderlab.xyz>
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