Skip to content

Escape blame popup log messages before embedding in inline JS - #243

Open
michael-o wants to merge 1 commit into
masterfrom
fix-blame-log-xss
Open

Escape blame popup log messages before embedding in inline JS#243
michael-o wants to merge 1 commit into
masterfrom
fix-blame-log-xss

Conversation

@michael-o

Copy link
Copy Markdown
Member

blame.php builds a per-revision hover-popup message for blame-popup.js by embedding each commit's log message directly into an inline <script> block, then blame-popup.js assigns it via innerHTML. The message was only passed through addslashes(), which escapes quote/backslash characters for the surrounding JS string literal but does nothing for HTML-significant characters.

A log message containing "</script><script>..." could close the legitimate <script> block early and inject an arbitrary script, and a message containing markup like "" would execute once assigned to innerHTML, even without breaking out of the script tag. This is the same class of stored XSS as d4de770/#228, but in a sink neither of those commits touched.

Apply xml_entities() before addslashes(): entity-encoding neutralizes real HTML metacharacters in the message, and addslashes() is still needed separately, since a message containing a raw "\uXXXX"-style sequence would otherwise be decoded into a real character by the browser's JS string-literal parser before the value ever reaches innerHTML, after entity-encoding has already run.

Also fix the line-flattening regex, which only matched a bare "\n" and left a stray "\r" in messages using CRLF line endings, causing display artifacts in the popup.

blame.php builds a per-revision hover-popup message for blame-popup.js
by embedding each commit's log message directly into an inline <script>
block, then blame-popup.js assigns it via innerHTML. The message was
only passed through addslashes(), which escapes quote/backslash
characters for the surrounding JS string literal but does nothing for
HTML-significant characters.

A log message containing "</script><script>..." could close the
legitimate <script> block early and inject an arbitrary script, and a
message containing markup like "<img src=x onerror=...>" would execute
once assigned to innerHTML, even without breaking out of the script
tag. This is the same class of stored XSS as d4de770/#228, but in a
sink neither of those commits touched.

Apply xml_entities() before addslashes(): entity-encoding neutralizes
real HTML metacharacters in the message, and addslashes() is still
needed separately, since a message containing a raw "\uXXXX"-style
sequence would otherwise be decoded into a real character by the
browser's JS string-literal parser before the value ever reaches
innerHTML, after entity-encoding has already run.

Also fix the line-flattening regex, which only matched a bare "\n" and
left a stray "\r" in messages using CRLF line endings, causing display
artifacts in the popup.
@michael-o michael-o self-assigned this Sep 2, 2026
@michael-o michael-o added this to the 2.9.0 milestone Sep 2, 2026
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.

1 participant