Fix verified web audit findings: CodeBlock XSS, block-mode send, store sync, parser grammar - #53
Merged
Merged
Conversation
…c, parsers)
WEB-E (HIGH): CodeBlock no longer renders the raw pre-Shiki fallback via
{@html}. Until the async Shiki highlight resolves, code lines render as
escaped text nodes, closing the XSS window where a code block containing
<img onerror=...> from a chat message executed.
WEB-B (HIGH): MessageInput send button now considers blockMode.body, so a
code-block-only message (inputValue empty, body in block mode) is sendable
via the button instead of being permanently disabled.
WEB-A (MED): markAllRead passes mark_seen:true so the server read cursor
advances (unread/mention dot no longer resurrect on reconnect);
sendMessage/forwardMessage strip the internal status field before publish
(no more stuck "Sending…" spinner on other clients); forwardMessage no
longer inflates the sender's own unread (self-author guard).
WEB-C (MED/LOW): mention name char-class aligned to the server authority
[\w-] (no dot) in mentions.js and dm-parser.js (utils.js already matched);
highlight-word match lowercases the word so uppercase words match; removed
dead utils.parseInlineCode and the dead _pendingActivity stash.
Tests: +8 (1292 -> 1300). Added CodeBlock pre-highlight escape test,
send-enabled/disabled block-mode tests, forward self-unread + wire
status-strip tests, uppercase highlight-word test, dot-terminator parser
tests; corrected the markAllRead call-shape assertion.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes a batch of verified audit findings in the web client (web files only).
High
CodeBlock.svelte) — the<pre>rendered the raw, unescapedcode.split('\n')fallback through{@html}during the always-present pre-Shiki window, so a code block containing<img onerror=...>from a chat message executed. The fallback now renders as escaped text nodes; only the already-safe Shiki output goes through{@html}.MessageInput.svelte) —disabledignoredblockMode.body, so a message whose body lived only in block mode could never be sent via the button (real clicks are dropped on a disabled button). The gate now considersblockMode?.body.Medium
markAllReadnever advanced the server cursor (mqtt-store) —comms_checkomittedmark_seen, so cleared unread/mention dots resurrected on the next reconnect/visibility-regain. Now passesmark_seen: true.status:'sending'leaked onto the wire (mqtt-store) —sendMessage/forwardMessagepublished the local-echostatus, leaving other clients with a permanent "Sending…" spinner. Both now stripstatusbefore publish (mirroringretryMessage).forwardMessageinflated the sender's own unread (mqtt-store) — the non-active-channel unread bump had no self-author guard. Added one.mentions.js,dm-parser.js) — aligned to the Python server authorityNAME_PATTERN = ^[\w-]{1,64}$(no dot).utils.jsalready matched. e.g.@bob.now stops atbob.notifications.svelte.js) — the body was lowercased but the word was not, so uppercase highlight words never matched. Now lowercases the word in the comparison.Low
utils.parseInlineCode(zero callers) and the dead_pendingActivitystash (written, never read).Tests
+8 net (1292 → 1300), zero skips: CodeBlock pre-highlight escape test, block-mode send enabled/disabled tests, forward self-unread + wire status-strip assertions, uppercase highlight-word test, dot-terminator parser tests; corrected the
markAllReadcall-shape assertion.Gates:
pnpm --dir web testgreen (3x, no flakiness, no stderr noise),pnpm --dir web buildgreen.🤖 Generated with Claude Code