fix(security): prevent XSS in library search snippets#3
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0c2fc83db8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const start = remaining.indexOf(SEARCH_SNIPPET_HIGHLIGHT_START); | ||
|
|
||
| if (start === -1) { |
There was a problem hiding this comment.
Handle literal highlight sentinel collisions
renderSnippet parses any occurrence of SEARCH_SNIPPET_HIGHLIGHT_START/END as markup boundaries, but those tokens now come from normal searchable content too, so a meeting transcript/title that literally contains these strings is mis-rendered. With an unmatched start token, the marker is stripped and text can be dropped (end === -1 path), and with both tokens present, arbitrary content is shown as highlighted even when it was not matched, which makes search results misleading for user-controlled data.
Useful? React with 👍 / 👎.
Motivation
snippet(...)output containing raw<mark>HTML that was rendered viadangerouslySetInnerHTML, allowing attacker-controlled meeting titles/transcripts to inject executable HTML/JS.Description
SEARCH_SNIPPET_HIGHLIGHT_STARTandSEARCH_SNIPPET_HIGHLIGHT_ENDinsrc/lib/searchSnippet.tsto be used as FTS highlight markers instead of<mark>tags.src/hooks/useLibrary.tsto request snippets with the sentinel markers by switching thesnippet(...)call tosnippet(meetings_fts, 1, $2, $3, '...', 32) AS snippetand passing the new sentinel constants as query parameters.dangerouslySetInnerHTMLusage by removingrenderSearchSnippetfromsrc/views/LibraryView.tsxand changingSearchResultRow(src/components/library/SearchResultRow.tsx) to a safe renderer that splits the snippet on the sentinel tokens and constructs text nodes and explicit<mark>React nodes, ensuring any HTML in content is treated as text.Testing
npm run build, which completed successfully.npm run test -- src/hooks/useLibrary.test.ts, and all tests passed (1 file, 5 tests).Codex Task