Repository navigation
fix(frontend): render string dialog content as text, not HTML (XSS) - #655
Merged
Merged
Conversation
dialogService rendered string `content` via innerHTML. RoundNew passes the import warnings as a string, and those contain file names taken from user-provided CSVs / Google Sheets / gists, so a name such as `<img src=x onerror=...>` ran script in the importing coordinator's session. Category imports were not affected (Commons titles cannot contain < or >). String content is now a text child. Display is otherwise unchanged: the dialog body has no white-space rule, so the '\n' separators were already collapsed under innerHTML. The only other string caller, the round delete confirmation, is plain text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Security fix (XSS, low–medium severity).
dialogServicerendered stringcontentwithinnerHTML. After a round import,RoundNew.vueshows the backend'swarnings(e.g. "not found" file names) and the disqualified list as string content. Those names come from user-provided CSV / Google Sheet / gist imports, so a list entry like<img src=x onerror=alert(1)>executed script in the importing coordinator's logged-in session. Category imports are not affected, because Commons titles cannot contain<or>. Exploiting this requires a coordinator to import a malicious list. No issue was filed for this.Change: a one-line fix. String content is now passed as a text child (
h('div', content)), so markup shows literally. Nothing else changes visually: the dialog body has nowhite-spacerule, so the\nseparators were already collapsed underinnerHTML. AlldialogService().showcallers were checked: the only other string caller (the round delete confirmation) is plain text, and the rest pass components.Testing
eslint src/andnpm run buildpass; backend tests pass. (npm run lintfails on master independently:--ignore-path .gitignorepoints at a missingfrontend/.gitignore.)vue/server-renderer: the payload is emitted escaped (<img …>) instead of as a live element. There is no frontend unit-test runner yet.<img src=x onerror=alert(1)>. Expect literal text and no alert.Not in this PR:
VoteEdit.vue:17rendersround.name(coordinator-set) throughv-html, which is the same class of issue (coordinator → juror). A separate PR will follow. Showing the warnings' line breaks, wrapping long names and moving the dialog strings to i18n will also follow separately.Written with Claude (Claude Code) on behalf of @lgelauff.
🤖 Generated with Claude Code