Skip to content

fix: prevent universal selector leakage in getStyl#582

Open
laasya2005 wants to merge 2 commits into
freeCodeCamp:mainfrom
laasya2005:fix/universal-selector-leakage
Open

fix: prevent universal selector leakage in getStyl#582
laasya2005 wants to merge 2 commits into
freeCodeCamp:mainfrom
laasya2005:fix/universal-selector-leakage

Conversation

@laasya2005
Copy link
Copy Markdown

Closes freeCodeCamp/freeCodeCamp#64218

CSS rules using universal selectors (*) like span[class~="one"] *:first-of-type could match queries for specific selectors that did not include *, causing overly broad student CSS to incorrectly pass challenge validation.

Changes:

  • Added _selectorHasUniversal() to detect * in CSS selectors
  • Modified getStyle() to skip rules containing * when the queried selector does not use it
  • Added 7 tests covering all four want/have universal selector combinations
  • Added shared CSS fixture for universal selector test cases

@laasya2005 laasya2005 requested a review from a team as a code owner April 8, 2026 23:21
Copy link
Copy Markdown
Contributor

@majestic-owl448 majestic-owl448 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. The core fix looks good, but the getStyleAny tests don't actually verify the universal selector guard.

In the three getStyleAny tests, the queried selectors (span[class~="one"] :first-of-type, span[class~="one"] p:first-of-type, span[class~="one"] p:first-of-type) don't exist anywhere in the CSS fixture. That means getStyle returns null for them via a plain exact-match miss, not because of the universal selector guard. The tests would pass even without the fix.

To properly test getStyleAny, the fixture needs a scenario where the bug would reproduce: a rule whose selectorText contains *, and a query that omits * but would otherwise match. The test should fail without the fix and pass with it.

Please also add the fixture and tests for the remaining cases (want *, CSS has no *; don't want *, CSS has no *) to mirror the four combinations already tested in getStyle.

Previously the guard (ruleHasUniversal && !wantsUniversal) could never
change getStyle's outcome because exact selectorText matching already
guaranteed that a string with * and one without * could never be equal.
JSDOM preserves * verbatim in selectorText, so the guard was unreachable.

Add _normalizeUniversal() to strip the universal type selector (* at the
start or after a combinator) before comparing, so a CSS rule written as
`span *:first-of-type` can be matched by the query `span *:first-of-type`
but is blocked by the guard when the query omits *, e.g. `span :first-of-type`.

Expand getStyleAny tests to mirror the four combinations already in getStyle:
- want *, CSS has * → truthy
- want *, CSS has no * → null
- don't want *, CSS has * → null (guard exercises the fix)
- don't want *, CSS has no * → truthy / null

The "should not match * rules against non-* selectors" test now fails without
the fix and passes with it, satisfying the reviewer's requirement.
@laasya2005 laasya2005 force-pushed the fix/universal-selector-leakage branch from f400800 to af5a35c Compare May 16, 2026 00:15
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.

CSSHelp issue with getStyleAny

2 participants