fix(packages): escape HTML special chars in serializeAttributes to prevent XSS#1670
Merged
luwes merged 5 commits intoJun 18, 2026
Merged
Conversation
|
@Jerricho93 is attempting to deploy a commit to the Mux Team on Vercel. A member of the Team first needs to authorize it. |
👷 Deploy request for vjs10-site pending review.Visit the deploys page to approve it
|
luwes
reviewed
Jun 9, 2026
luwes
reviewed
Jun 9, 2026
luwes
reviewed
Jun 9, 2026
luwes
requested changes
Jun 9, 2026
luwes
left a comment
Collaborator
There was a problem hiding this comment.
would like some small changes but looks good overall!
…event XSS Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n in e2e XSS tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
530412d to
449c141
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 449c141. Configure here.
…ideo Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.

Summary
serializeAttributesinterpolated attribute values directly into HTML strings without encoding. Because the result is assigned toshadowRoot.innerHTMLat construction time, and Shadow DOM does not sandbox script execution, any attribute value containing"(e.g. a user-controlledposter,src, orcrossorigin) could break out of the attribute and inject event handlers or<script>siblings into the shadow root.Changes per sink:
utils: add privateescapeAttributeValuethat encodes&,<,>,"(ampersand first to prevent double-encoding); apply inserializeAttributeshtml/BackgroundVideo: remove the local duplicateserializeAttributes; import the shared util andpickagainst the existing attribute allowlisthtml/define/background: remove dead_attrsparameter (was passed to a template that never interpolated it)icons/scripts/build: inlineesc()in the generatedrenderIconfunction body to close the codegen sinksite/build-ejected-skins: extend the partial localescapeAttributeValueto also cover<and>Testing
packages/utils/src/dom/tests/attributes.test.ts: 9 cases covering all four chars, boolean branch, ampersand-first ordering regression, andnamedNodeMapToObjectraw-value preservationpackages/html/src/media/background-video/tests/background-video.test.ts: quote breakout, angle-bracket injection, non-allowlisted attribute filtering, boolean attrs, safe value round-trippackages/core/.../custom-media-element.test.ts:describe('XSS prevention')with 4 casesapps/e2e/tests/xss-prevention.spec.ts: 3 Playwright tests exercising the construction-time path viacontainer.innerHTMLValidation
Known issue (follow-up)
CustomMediaElementhas a pre-existing attribute routing inconsistency:getAttrsFromPropsuses.toLowerCase()to buildobservedAttributes(e.g.crossorigin,controlslist,disableremoteplayback), while#defineuseskebabCaseto keymediaHostAttrToProp(e.g.cross-origin,controls-list,disable-remote-playback). Because these never match, multi-word attributes are never added to the disallowed set and always flow throughserializeAttributesrather thanattributeChangedCallback. This means post-constructionsetAttributecalls for those attributes do not sync to the media host setter. This fix makesserializeAttributessafe, closing the injection vector — but the routing inconsistency itself should be tracked and corrected separately.Closes #1562
Note
High Risk
Security fix on HTML string assembly used at custom-element construction; behavior change for attribute values containing
&<>"but intended to block script/event injection in shadow templates.Overview
Closes an XSS path where unescaped attribute values were interpolated into HTML assigned to
shadowRoot.innerHTML(and similar codegen sinks), allowing quote/angle-bracket breakout into event handlers or extra nodes inside shadow roots.serializeAttributesin@videojs/utils/domnow runs values throughescapeHtml(&,<,>,", with ampersand first).BackgroundVideodrops its local serializer and uses the shared helper with an existing video-attribute allowlist viapick.background-video-skinstops passing unused attrs into a static template.The same escaping pattern is applied to generated
renderIconoutput (icons build) and ejected skin HTML (build-ejected-skins), including</>on icon names and attrs.Coverage adds unit tests for
serializeAttributes/escapeHtml, XSS cases onCustomMediaElementandBackgroundVideo, and Playwright e2e onhls-videoconstruction viainnerHTML.Reviewed by Cursor Bugbot for commit 101bd4a. Bugbot is set up for automated code reviews on this repo. Configure here.