Skip to content

fix(core,studio): escape user values in querySelector attribute selectors#1586

Open
miguel-heygen wants to merge 1 commit into
mainfrom
fix/css-selector-escape
Open

fix(core,studio): escape user values in querySelector attribute selectors#1586
miguel-heygen wants to merge 1 commit into
mainfrom
fix/css-selector-escape

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Extracts queryByAttr(root, attr, value, tag?) to packages/core/src/utils/cssSelector.ts — queries DOM by attribute presence then compares with exact ===, zero injection surface
  • Fixes all 12 sites across core and studio that interpolated raw user-authored values into querySelector attribute selectors
  • Node-side (core compiler/parser): uses queryByAttr — no selector string interpolation at all
  • Browser-side (runtime, studio): uses native CSS.escape()

A " in a composition ID, script src URL, or data-start element reference would produce a malformed CSS selector that throws Attribute selector didn't terminate in css-select, crashing the entire pipeline.

Supersedes #1568 which fixed only the 3 bundler sites.

Approach

Instead of escaping values and interpolating into selector strings, queryByAttr queries for attribute presence ([attr]) then compares with ===. The user value never touches a CSS selector — there is nothing to escape and nothing to inject.

Fixed sites

Package File Variable Risk
core htmlBundler.ts:627,828 src / extSrc (script src) Medium
core htmlBundler.ts:860 compId (composition ID) Medium
core inlineSubCompositions.ts:228 compId Medium
core htmlParser.ts:522 elementId (public API param) Medium
core picker.ts:100-102 compositionId, compositionSrc High
studio timelineIframeHelpers.ts:298,306 startAttr (user-authored) Medium-High
studio timelineIframeHelpers.ts:403 existing.id (DOM id) Medium
studio timelineElementHelpers.ts:286-287 id (clip id + raw class selector) High
studio timelineDOM.ts:126 clip.compositionId Medium
studio domEditingElement.ts:245 selection.hfId Low
studio LayersPanel.tsx:129 layer.hfId Low

Test plan

  • Bundler tests pass (36/36)
  • Full CI green
  • Verify compositions with special characters in IDs still bundle/preview correctly

@miguel-heygen miguel-heygen force-pushed the fix/css-selector-escape branch 2 times, most recently from bb69548 to ccfcafa Compare June 19, 2026 04:43
…tors

Extract cssAttrSelector to packages/core/src/utils/cssSelector.ts and
use it (or CSS.escape for browser-side code) at all 12 sites that
previously interpolated raw user-authored values into querySelector
attribute selectors. A " in a composition ID, script src, or
data-start value would produce a malformed selector that throws.

Node-side (core compiler/parser): uses the shared cssAttrSelector.
Browser-side (runtime, studio): uses native CSS.escape().

Supersedes #1568 which fixed only the 3 bundler sites.
@miguel-heygen miguel-heygen force-pushed the fix/css-selector-escape branch from ccfcafa to 22ff0dd Compare June 19, 2026 05:52
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