Firefox · Core
CVE-2026-118011
Logic Error in Core
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
servo/components/style/properties/data.pyservo/components/style/properties/longhands.tomlservo/components/style/properties/shorthands.tomltesting/web-platform/tests/css/css-cascade/declaration-context.html
Patch
diff --git a/servo/components/style/properties/data.py b/servo/components/style/properties/data.py
index d3240df95a4..5e3c9ab7b5d 100644
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -177,7 +177,10 @@ def rule_values_from_arg(rule_types):
return DEFAULT_RULES
mask = 0
for rule in rule_types:
+ assert rule != "scope", "scope is just derived from style"
mask |= RULE_VALUES[rule]
+ if rule == "style":
+ mask |= SCOPE_RULE
return mask
diff --git a/servo/components/style/properties/longhands.toml b/servo/components/style/properties/longhands.toml
index 371ce97e63f..652629551ba 100644
--- a/servo/components/style/properties/longhands.toml
+++ b/servo/components/style/properties/longhands.toml
@@ -168,7 +168,7 @@ parse_method = "parse_block"
spec = "https://drafts.csswg.org/css-align/#align-self-property"
extra_prefixes = ["webkit"]
animation_type = "discrete"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
affects = "layout"
[alignment-baseline]
@@ -206,7 +206,7 @@ vector = { need_index = true }
animation_type = "none"
extra_prefixes = ["moz:layout.css.prefixes.animations", "webkit"]
spec = "https://drafts.csswg.org/css-animations/#propdef-animation-delay"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[animation-direction]
@@ -217,7 +217,7 @@ vector = { need_index = true }
animation_type = "none"
extra_prefixes = ["moz:layout.css.prefixes.animations", "webkit"]
spec = "https://drafts.csswg.org/css-animations/#propdef-animation-direction"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[animation-duration]
@@ -238,7 +238,7 @@ vector = { need_index = true }
animation_type = "none"
extra_prefixes = ["moz:layout.css.prefixes.animations", "webkit"]
spec = "https://drafts.csswg.org/css-animations/#propdef-animation-fill-mode"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[animation-iteration-count]
@@ -248,7 +248,7 @@ struct = "ui"
vector = { need_index = true }
animation_type = "none"
extra_prefixes = ["moz:layout.css.prefixes.animations", "webkit"]
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
spec = "https://drafts.csswg.org/css-animations/#propdef-animation-iteration-count"
affects = ""
@@ -259,7 +259,7 @@ struct = "ui"
vector = { need_index = true }
animation_type = "none"
extra_prefixes = ["moz:layout.css.prefixes.animations", "webkit"]
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
spec = "https://drafts.csswg.org/css-animations/#propdef-animation-name"
affects = ""
@@ -271,7 +271,7 @@ vector = { need_index = true }
animation_type = "none"
extra_prefixes = ["moz:layout.css.prefixes.animations", "webkit"]
spec = "https://drafts.csswg.org/css-animations/#propdef-animation-play-state"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[animation-range-end]
@@ -283,7 +283,7 @@ vector = { need_index = true }
animation_type = "none"
gecko_pref = "layout.css.scroll-driven-animations.enabled"
spec = "https://drafts.csswg.org/scroll-animations-1/#animation-range-end"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[animation-range-start]
@@ -295,7 +295,7 @@ vector = { need_index = true }
animation_type = "none"
gecko_pref = "layout.css.scroll-driven-animations.enabled"
spec = "https://drafts.csswg.org/scroll-animations-1/#animation-range-start"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[animation-timeline]
@@ -307,7 +307,7 @@ vector = { need_index = true }
animation_type = "none"
gecko_pref = "layout.css.scroll-driven-animations.enabled"
spec = "https://drafts.csswg.org/css-animations-2/#propdef-animation-timeline"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[animation-timing-function]
@@ -439,7 +439,7 @@ logical = true
logical_group = "size"
parse_method = "parse_size_for_width_or_height"
spec = "https://drafts.csswg.org/css-logical-props/#propdef-block-size"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -458,7 +458,7 @@ struct = "position"
flags = "SCROLL_LINKED_EFFECTIVE"
spec = "https://www.w3.org/TR/CSS2/visuren.html#propdef-bottom"
allow_quirks = true
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
gecko_ffi_name = "mOffset.2"
servo_restyle_damage = "rebuild_box"
logical_group = "inset"
@@ -1140,7 +1140,7 @@ allow_quirks = true
parse_method = "parse_size_for_width_or_height"
flags = "SCROLL_LINKED_EFFECTIVE"
spec = "https://drafts.csswg.org/css-box/#propdef-height"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -1171,7 +1171,7 @@ logical = true
logical_group = "size"
parse_method = "parse_size_for_width_or_height"
spec = "https://drafts.csswg.org/css-logical-props/#propdef-inline-size"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -1180,7 +1180,7 @@ type = "Inset"
initial = "computed::Inset::auto()"
struct = "position"
spec = "https://drafts.csswg.org/css-logical-props/#propdef-inset-block-end"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
logical = true
logical_group = "inset"
affects = "layout"
@@ -1190,7 +1190,7 @@ type = "Inset"
initial = "computed::Inset::auto()"
struct = "position"
spec = "https://drafts.csswg.org/css-logical-props/#propdef-inset-block-start"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
logical = true
logical_group = "inset"
affects = "layout"
@@ -1200,7 +1200,7 @@ type = "Inset"
initial = "computed::Inset::auto()"
struct = "position"
spec = "https://drafts.csswg.org/css-logical-props/#propdef-inset-inline-end"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
logical = true
logical_group = "inset"
affects = "layout"
@@ -1210,7 +1210,7 @@ type = "Inset"
initial = "computed::Inset::auto()"
struct = "position"
spec = "https://drafts.csswg.org/css-logical-props/#propdef-inset-inline-start"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
logical = true
logical_group = "inset"
affects = "layout"
@@ -1241,7 +1241,7 @@ struct = "position"
parse_method = "parse_inline"
spec = "https://drafts.csswg.org/css-align/#justify-self-property"
animation_type = "discrete"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
affects = "layout"
[left]
@@ -1251,7 +1251,7 @@ struct = "position"
flags = "SCROLL_LINKED_EFFECTIVE"
spec = "https://www.w3.org/TR/CSS2/visuren.html#propdef-left"
allow_quirks = true
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
gecko_ffi_name = "mOffset.3"
servo_restyle_damage = "rebuild_box"
logical_group = "inset"
@@ -1352,7 +1352,7 @@ struct = "position"
logical = true
logical_group = "max-size"
spec = "https://drafts.csswg.org/css-logical-props/#propdef-block-size"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -1363,7 +1363,7 @@ struct = "position"
logical_group = "max-size"
allow_quirks = true
spec = "https://drafts.csswg.org/css-box/#propdef-height"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -1374,7 +1374,7 @@ struct = "position"
logical = true
logical_group = "max-size"
spec = "https://drafts.csswg.org/css-logical-props/#propdef-inline-size"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -1385,7 +1385,7 @@ struct = "position"
logical_group = "max-size"
allow_quirks = true
spec = "https://drafts.csswg.org/css-box/#propdef-width"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -1396,7 +1396,7 @@ struct = "position"
logical = true
logical_group = "min-size"
spec = "https://drafts.csswg.org/css-logical-props/#propdef-block-size"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -1407,7 +1407,7 @@ struct = "position"
logical_group = "min-size"
allow_quirks = true
spec = "https://drafts.csswg.org/css-box/#propdef-height"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -1418,7 +1418,7 @@ struct = "position"
logical = true
logical_group = "min-size"
spec = "https://drafts.csswg.org/css-logical-props/#propdef-inline-size"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -1429,7 +1429,7 @@ struct = "position"
logical_group = "min-size"
allow_quirks = true
spec = "https://drafts.csswg.org/css-box/#propdef-width"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -1741,7 +1741,7 @@ initial = "computed::PositionAnchor::normal()"
struct = "position"
engine = "gecko"
animation_type = "discrete"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
spec = "https://drafts.csswg.org/css-anchor-position-1/#propdef-position-anchor"
affects = "layout"
@@ -1750,7 +1750,7 @@ type = "PositionArea"
initial = "computed::PositionArea::none()"
struct = "position"
animation_type = "discrete"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_pref = "layout.unimplemented"
spec = "https://drafts.csswg.org/css-anchor-position-1/#typedef-position-area"
affects = "layout"
@@ -1818,7 +1818,7 @@ struct = "position"
flags = "SCROLL_LINKED_EFFECTIVE"
spec = "https://www.w3.org/TR/CSS2/visuren.html#propdef-right"
allow_quirks = true
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
gecko_ffi_name = "mOffset.1"
servo_restyle_damage = "rebuild_box"
logical_group = "inset"
@@ -2093,7 +2093,7 @@ struct = "position"
flags = "SCROLL_LINKED_EFFECTIVE"
spec = "https://www.w3.org/TR/CSS2/visuren.html#propdef-top"
allow_quirks = true
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
gecko_ffi_name = "mOffset.0"
servo_restyle_damage = "rebuild_box"
logical_group = "inset"
@@ -2281,7 +2281,7 @@ vector = { need_index = true }
animation_type = "none"
gecko_pref = "layout.css.scroll-driven-animations.enabled"
spec = "https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-axis"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[scroll-timeline-name]
@@ -2293,7 +2293,7 @@ vector = { need_index = true }
animation_type = "none"
gecko_pref = "layout.css.scroll-driven-animations.enabled"
spec = "https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-name"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[view-timeline-axis]
@@ -2305,7 +2305,7 @@ vector = { need_index = true }
animation_type = "none"
gecko_pref = "layout.css.scroll-driven-animations.enabled"
spec = "https://drafts.csswg.org/scroll-animations-1/#view-timeline-axis"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[view-timeline-inset]
@@ -2317,7 +2317,7 @@ vector = { need_index = true }
animation_type = "none"
gecko_pref = "layout.css.scroll-driven-animations.enabled"
spec = "https://drafts.csswg.org/scroll-animations-1/#view-timeline-axis"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[view-timeline-name]
@@ -2329,7 +2329,7 @@ vector = { need_index = true }
animation_type = "none"
gecko_pref = "layout.css.scroll-driven-animations.enabled"
spec = "https://drafts.csswg.org/scroll-animations-1/#view-timeline-name"
-rule_types_allowed = ["style", "scope"]
+rule_types_allowed = ["style"]
affects = ""
[view-transition-class]
@@ -2470,7 +2470,7 @@ allow_quirks = true
parse_method = "parse_size_for_width_or_height"
flags = "SCROLL_LINKED_EFFECTIVE"
spec = "https://drafts.csswg.org/css-box/#propdef-width"
-rule_types_allowed = ["style", "keyframe", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -3276,7 +3276,7 @@ logical_group = "margin"
gecko_ffi_name = "mMargin.0"
flags = "SCROLL_LINKED_EFFECTIVE"
spec = "https://drafts.csswg.org/css-box/#propdef-margin-top"
-rule_types_allowed = ["style", "keyframe", "page", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "page", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -3289,7 +3289,7 @@ logical_group = "margin"
gecko_ffi_name = "mMargin.1"
flags = "SCROLL_LINKED_EFFECTIVE"
spec = "https://drafts.csswg.org/css-box/#propdef-margin-right"
-rule_types_allowed = ["style", "keyframe", "page", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "page", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -3302,7 +3302,7 @@ logical_group = "margin"
gecko_ffi_name = "mMargin.2"
flags = "SCROLL_LINKED_EFFECTIVE"
spec = "https://drafts.csswg.org/css-box/#propdef-margin-bottom"
-rule_types_allowed = ["style", "keyframe", "page", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "page", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -3315,7 +3315,7 @@ logical_group = "margin"
gecko_ffi_name = "mMargin.3"
flags = "SCROLL_LINKED_EFFECTIVE"
spec = "https://drafts.csswg.org/css-box/#propdef-margin-left"
-rule_types_allowed = ["style", "keyframe", "page", "scope", "position-try"]
+rule_types_allowed = ["style", "keyframe", "page", "position-try"]
servo_restyle_damage = "rebuild_box"
affects = "layout"
@@ -3328,7 +3328,7 @@ logical_group = "margin"
gecko_ffi_name = "mMargin.4"
flags = "SCROLL_LINKED_EFFECTIVE"
... (file diff truncated)
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/testing/web-platform/tests/css/css-cascade/declaration-context.html b/testing/web-platform/tests/css/css-cascade/declaration-context.html
index d79b5881645..19e803a4dc6 100644
--- a/testing/web-platform/tests/css/css-cascade/declaration-context.html
+++ b/testing/web-platform/tests/css/css-cascade/declaration-context.html
@@ -135,6 +135,52 @@ test(t => {
assert_equals(style.getPropertyValue('display'), 'grid');
}, 'Declarations after a nested @page inside @scope are not restricted');
+const computed = getComputedStyle(document.documentElement);
+const allProperties = Array.from(computed, name => [name, computed.getPropertyValue(name)]);
+const allDeclarations = allProperties.map(([name, value]) => `${name}: ${value};`).join(' ');
+
+function checkMatches(scoped, unscoped) {
+ for (const [name] of allProperties) {
+ assert_equals(scoped.getPropertyValue(name), unscoped.getPropertyValue(name), name);
+ }
+}
+
+function testScopedMatches(description, getUnscopedStyle, getScopedStyle) {
+ test(t => {
+ checkMatches(getScopedStyle(t, allDeclarations), getUnscopedStyle(t, allDeclarations));
+ }, `${description} parses the same declarations`);
+
+ test(t => {
+ const unscoped = getUnscopedStyle(t, '');
+ const scoped = getScopedStyle(t, '');
+ for (const [name, value] of allProperties) {
+ unscoped.setProperty(name, value);
+ scoped.setProperty(name, value);
+ }
+ checkMatches(scoped, unscoped);
+ }, `${description} accepts the same properties set`);
+}
+
+for (const [kind, ruleText, getStyle] of [
+ ['@position-try', body => `@position-try --fallback { ${body} }`, rule => rule.style],
+ ['@keyframes', body => `@keyframes k { to { ${body} } }`, rule => rule.cssRules[0].style],
+ ['@page', body => `@page { ${body} }`, rule => rule.style],
+]) {
+ testScopedMatches(
+ `${kind} inside @scope vs. in the stylesheet`,
+ (t, body) => getStyle(createSheet(t, ruleText(body)).cssRules[0]),
+ (t, body) => getStyle(createSheet(t, `@scope (:root) { ${ruleText(body)} }`).cssRules[0].cssRules[0]));
+}
+
+testScopedMatches(
+ 'Bare declarations inside @scope vs. in a style rule',
+ (t, body) => createSheet(t, `:root { --unused: 0; ${body} }`).cssRules[0].style,
+ (t, body) => {
+ const rule = createSheet(t, `@scope (:root) { --unused: 0; ${body} }`).cssRules[0].cssRules[0];
+ assert_true(rule instanceof CSSNestedDeclarations);
+ return rule.style;
+ });
+
test(t => {
const groups = [':root', '@scope (:root)', '@media all'];
const sheet = createSheet(t, wrapRules(groups, ''));
Loading diff…
References
On This Page