From e3de39893f724005537059b474a69f6e24a71731 Mon Sep 17 00:00:00 2001
From: Tim van der Lippe
Date: Sun, 7 Sep 2025 14:31:40 +0200
Subject: [PATCH] Disable scripting when sandbox flag is set (#39163)
While I adding spec comments to the CSP crate, I discovered two issues:
1. We should only use the last sandbox value (WPT test added)
2. We weren't checking for the scripting sandbox flag in document
Also, the autoplay test should have allowed scripts to run, otherwise
the test doesn't run. Since we weren't checking the flag before, the
test ran fine for Servo. However, it wouldn't run for other browsers.
Also realized that an existing test was pointing to a non-existent file
(since it doesn't have `.sub`). Updated that and confirmed that in other
browsers it now properly works (it no longer shows a 404). However,
Servo now fails that test as we don't fire an load event.
Part of #913
Signed-off-by: Tim van der Lippe
---
Cargo.lock | 2 +-
components/script/dom/document.rs | 21 ++-
components/script/dom/eventtarget.rs | 2 +-
.../script/dom/html/htmlscriptelement.rs | 6 +-
tests/wpt/meta/MANIFEST.json | 134 ++++++++++++++----
.../sandbox/sandbox-empty.sub.html.ini | 3 +
...ed-types-sandbox-no-allow-scripts.html.ini | 3 -
.../sandbox/autoplay-disabled-by-csp.html | 29 ++++
.../sandbox/sandbox-empty.sub.html | 2 +-
.../sandbox/sandbox-last-directive-csp.html | 18 +++
.../sandbox/support/autoplay.html | 1 +
.../sandbox/support/autoplay.html.headers | 1 +
.../sandboxed-last-directive-csp.headers | 1 +
.../support/sandboxed-last-directive-csp.html | 4 +
.../sandboxed-post-message-to-parent.headers | 1 +
15 files changed, 180 insertions(+), 48 deletions(-)
create mode 100644 tests/wpt/meta/content-security-policy/sandbox/sandbox-empty.sub.html.ini
delete mode 100644 tests/wpt/meta/trusted-types/trusted-types-sandbox-no-allow-scripts.html.ini
create mode 100644 tests/wpt/tests/content-security-policy/sandbox/autoplay-disabled-by-csp.html
create mode 100644 tests/wpt/tests/content-security-policy/sandbox/sandbox-last-directive-csp.html
create mode 100644 tests/wpt/tests/content-security-policy/sandbox/support/autoplay.html
create mode 100644 tests/wpt/tests/content-security-policy/sandbox/support/autoplay.html.headers
create mode 100644 tests/wpt/tests/content-security-policy/sandbox/support/sandboxed-last-directive-csp.headers
create mode 100644 tests/wpt/tests/content-security-policy/sandbox/support/sandboxed-last-directive-csp.html
create mode 100644 tests/wpt/tests/content-security-policy/sandbox/support/sandboxed-post-message-to-parent.headers
diff --git a/Cargo.lock b/Cargo.lock
index 02730d18a27..ec1075c4f63 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1650,7 +1650,7 @@ dependencies = [
[[package]]
name = "content-security-policy"
version = "0.5.4"
-source = "git+https://github.com/servo/rust-content-security-policy?branch=servo-csp#fc927dfefb1fdc052fa4fa18c2ca3c3f6b87047b"
+source = "git+https://github.com/servo/rust-content-security-policy?branch=servo-csp#b437ae2001616161ce4729b49408e7785b2f6960"
dependencies = [
"base64 0.22.1",
"bitflags 2.9.4",
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 25579678307..ab28b2b85d4 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -357,9 +357,6 @@ pub(crate) struct Document {
asap_in_order_scripts_list: PendingInOrderScriptVec,
///
asap_scripts_set: DomRefCell>>,
- ///
- /// True if scripting is enabled for all scripts in this document
- scripting_enabled: bool,
///
/// Current identifier of animation frame callback
animation_frame_ident: Cell,
@@ -1115,14 +1112,17 @@ impl Document {
}
/// Return whether scripting is enabled or not
- pub(crate) fn is_scripting_enabled(&self) -> bool {
- self.scripting_enabled
- }
-
- /// Return whether scripting is enabled or not
- ///
+ ///
pub(crate) fn scripting_enabled(&self) -> bool {
- self.has_browsing_context()
+ // Scripting is enabled for a node node if node's node document's browsing context is non-null,
+ // and scripting is enabled for node's relevant settings object.
+ self.has_browsing_context() &&
+ // Either settings's global object is not a Window object,
+ // or settings's global object's associated Document's active sandboxing flag
+ // set does not have its sandboxed scripts browsing context flag set.
+ !self.has_active_sandboxing_flag(
+ SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
+ )
}
/// Return the element that currently has focus.
@@ -3365,7 +3365,6 @@ impl Document {
deferred_scripts: Default::default(),
asap_in_order_scripts_list: Default::default(),
asap_scripts_set: Default::default(),
- scripting_enabled: has_browsing_context,
animation_frame_ident: Cell::new(0),
animation_frame_list: DomRefCell::new(VecDeque::new()),
running_animation_callbacks: Cell::new(false),
diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs
index b35c1bf6a58..1ffc1e59707 100644
--- a/components/script/dom/eventtarget.rs
+++ b/components/script/dom/eventtarget.rs
@@ -720,7 +720,7 @@ impl EventTarget {
};
// Step 3.2
- if !document.is_scripting_enabled() {
+ if !document.scripting_enabled() {
return None;
}
diff --git a/components/script/dom/html/htmlscriptelement.rs b/components/script/dom/html/htmlscriptelement.rs
index ddd98330179..8921dc9fa5b 100644
--- a/components/script/dom/html/htmlscriptelement.rs
+++ b/components/script/dom/html/htmlscriptelement.rs
@@ -688,7 +688,7 @@ impl HTMLScriptElement {
}
// Step 17. If scripting is disabled for el, then return.
- if !doc.is_scripting_enabled() {
+ if !doc.scripting_enabled() {
return;
}
@@ -1093,7 +1093,7 @@ impl HTMLScriptElement {
// TODO use a settings object rather than this element's document/window
// Step 2
let document = self.owner_document();
- if !document.is_fully_active() || !document.is_scripting_enabled() {
+ if !document.is_fully_active() || !document.scripting_enabled() {
return;
}
@@ -1130,7 +1130,7 @@ impl HTMLScriptElement {
// TODO use a settings object rather than this element's document/window
// Step 2
let document = self.owner_document();
- if !document.is_fully_active() || !document.is_scripting_enabled() {
+ if !document.is_fully_active() || !document.scripting_enabled() {
return;
}
diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json
index bc5552f1cb4..d998116bafe 100644
--- a/tests/wpt/meta/MANIFEST.json
+++ b/tests/wpt/meta/MANIFEST.json
@@ -5070,7 +5070,9 @@
"545f2919b55ffe31f942e547d5299c00ee89d715",
[
null,
- {}
+ {
+ "testdriver": true
+ }
]
],
"table-col-and-dead-row-group-crash.html": [
@@ -8076,7 +8078,9 @@
"63111d03e3fab4673ec4d14cff6ad5737fd4f39c",
[
null,
- {}
+ {
+ "testdriver": true
+ }
]
]
}
@@ -8259,7 +8263,9 @@
"39acf9eca17597838a4eec54f31d70be3f9abbb7",
[
null,
- {}
+ {
+ "testdriver": true
+ }
]
]
},
@@ -9121,7 +9127,9 @@
"24bb1ca19e11c516299d8b7cc6ceae21ec981566",
[
null,
- {}
+ {
+ "testdriver": true
+ }
]
]
}
@@ -10320,7 +10328,9 @@
"853884b99301e22383e0fd0936cf154beab5e93e",
[
null,
- {}
+ {
+ "testdriver": true
+ }
]
]
},
@@ -38416,7 +38426,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
]
}
@@ -196055,7 +196067,7 @@
"grid-items-relative-positioned-containing-block-001.html": [
"7683e485c05caea40361416bc533dc95fbfcd837",
[
- "css/css-grid/grid-items/grid-items-relative-positioned-containing-block-001.html",
+ null,
[
[
"/css/reference/ref-filled-green-100px-square.xht",
@@ -196068,7 +196080,7 @@
"grid-items-relative-positioned-containing-block-002.html": [
"1e7a754f74da30e327feb06e05527012d1a3917d",
[
- "css/css-grid/grid-items/grid-items-relative-positioned-containing-block-002.html",
+ null,
[
[
"/css/reference/ref-filled-green-100px-square.xht",
@@ -196081,7 +196093,7 @@
"grid-items-relative-positioned-containing-block-003.html": [
"be0305181914e9b872d0ef1bdc801f974c5918f7",
[
- "css/css-grid/grid-items/grid-items-relative-positioned-containing-block-003.html",
+ null,
[
[
"/css/reference/ref-filled-green-100px-square.xht",
@@ -196094,7 +196106,7 @@
"grid-items-relative-positioned-containing-block-004.html": [
"61d50a10c10290b55a7439d6b59528f01accc4bf",
[
- "css/css-grid/grid-items/grid-items-relative-positioned-containing-block-004.html",
+ null,
[
[
"/css/reference/ref-filled-green-100px-square.xht",
@@ -196107,7 +196119,7 @@
"grid-items-relative-positioned-containing-block-005.html": [
"4473cb8d2ba4ea847669cde34ce10e27e6bfb001",
[
- "css/css-grid/grid-items/grid-items-relative-positioned-containing-block-005.html",
+ null,
[
[
"/css/reference/ref-filled-green-100px-square.xht",
@@ -196120,7 +196132,7 @@
"grid-items-relative-positioned-containing-block-006.html": [
"79350eac516f2850545a6446f570c6c7778a4e3b",
[
- "css/css-grid/grid-items/grid-items-relative-positioned-containing-block-006.html",
+ null,
[
[
"/css/reference/ref-filled-green-100px-square.xht",
@@ -197559,7 +197571,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
],
"grid-layout-stale-002.html": [
@@ -197572,7 +197586,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
],
"grid-margins-no-collapse-001.html": [
@@ -246133,7 +246149,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
],
"interaction-with-placeholder.html": [
@@ -278427,7 +278445,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
]
},
@@ -312839,7 +312859,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
],
"hit-test-unrelated-element.html": [
@@ -312852,7 +312874,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
],
"iframe-and-main-frame-transition-new-main-new-iframe.html": [
@@ -344798,7 +344822,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
],
"root-siblings.html": [
@@ -346752,7 +346778,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
],
"backdrop-inherit.html": [
@@ -346765,7 +346793,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
],
"backdrop-object.html": [
@@ -346793,7 +346823,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
]
}
@@ -359365,7 +359397,7 @@
"input-date-content-size.html": [
"d026771f3c89c736b397db6a10c15fde5d73a3a8",
[
- "html/rendering/widgets/input-date-content-size.html",
+ null,
[
[
"/html/rendering/widgets/input-date-content-size-ref.html",
@@ -359456,7 +359488,7 @@
"input-time-content-size.html": [
"4a378f6923a8910b96f8afa84125a8fbac4a5d05",
[
- "html/rendering/widgets/input-time-content-size.html",
+ null,
[
[
"/html/rendering/widgets/input-time-content-size-ref.html",
@@ -365315,7 +365347,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
],
"testdriver-in-ref.html": [
@@ -365341,7 +365375,9 @@
"=="
]
],
- {}
+ {
+ "testdriver": true
+ }
]
]
},
@@ -404513,6 +404549,14 @@
},
"sandbox": {
"support": {
+ "autoplay.html": [
+ "62d0adc3d204f2df9337bf30343591bfb1958e67",
+ []
+ ],
+ "autoplay.html.headers": [
+ "09e65834224c8b917d0a6a2fae17f79ff251fcb6",
+ []
+ ],
"empty.html": [
"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
[]
@@ -404537,6 +404581,18 @@
"c7e4e7cc5bd3fa25851c1e26c3c04eb95050d94b",
[]
],
+ "sandboxed-last-directive-csp.headers": [
+ "371abe3b936e686c901cc9f6f366b8c68e6f3f8b",
+ []
+ ],
+ "sandboxed-last-directive-csp.html": [
+ "9480e521de21ef930674721de943f96e1fd1219a",
+ []
+ ],
+ "sandboxed-post-message-to-parent.headers": [
+ "0368ae01896a2cadb6019ab2c1eb5346d9c3b764",
+ []
+ ],
"sandboxed-post-message-to-parent.html": [
"ef4b1a0b95a7e00275c423d49dd28f98545950d3",
[]
@@ -582583,6 +582639,13 @@
]
},
"sandbox": {
+ "autoplay-disabled-by-csp.html": [
+ "1d1ed0e50b7182ed0d1f8ab7d1b7c7b98e709030",
+ [
+ null,
+ {}
+ ]
+ ],
"iframe-inside-csp.sub.html": [
"cd402bdba0198bf763e1733004c2005614b9a542",
[
@@ -582619,7 +582682,14 @@
]
],
"sandbox-empty.sub.html": [
- "47034710203a1fb8a3326cd7c8d8367166837628",
+ "47c3aa1e3657cf2eb5acfeb06bd1936b6e117d0f",
+ [
+ null,
+ {}
+ ]
+ ],
+ "sandbox-last-directive-csp.html": [
+ "b4b2cdbe3296dff091594f73dafb4f4791e5ca72",
[
null,
{}
@@ -762513,7 +762583,12 @@
"5b05e2374e2b4b451a0f98eabd36a6e72a03f933",
[
null,
- {}
+ {
+ "testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ]
+ }
]
]
}
@@ -762745,6 +762820,9 @@
"script",
"/resources/testdriver.js?feature=bidi"
]
+ ],
+ "testdriver_features": [
+ "bidi"
]
}
]
diff --git a/tests/wpt/meta/content-security-policy/sandbox/sandbox-empty.sub.html.ini b/tests/wpt/meta/content-security-policy/sandbox/sandbox-empty.sub.html.ini
new file mode 100644
index 00000000000..d9a90039a88
--- /dev/null
+++ b/tests/wpt/meta/content-security-policy/sandbox/sandbox-empty.sub.html.ini
@@ -0,0 +1,3 @@
+[sandbox-empty.sub.html]
+ [Expecting logs: ["PASS2"\]]
+ expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-sandbox-no-allow-scripts.html.ini b/tests/wpt/meta/trusted-types/trusted-types-sandbox-no-allow-scripts.html.ini
deleted file mode 100644
index b608e9999bc..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-sandbox-no-allow-scripts.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[trusted-types-sandbox-no-allow-scripts.html]
- [Trusted Types CSP directives don't affect the behavior of sandboxed page without allow-scripts.]
- expected: FAIL
diff --git a/tests/wpt/tests/content-security-policy/sandbox/autoplay-disabled-by-csp.html b/tests/wpt/tests/content-security-policy/sandbox/autoplay-disabled-by-csp.html
new file mode 100644
index 00000000000..1d1ed0e50b7
--- /dev/null
+++ b/tests/wpt/tests/content-security-policy/sandbox/autoplay-disabled-by-csp.html
@@ -0,0 +1,29 @@
+
+
+
+
+ Test that autoplay is blocked by a document's active sandboxing flags
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/tests/content-security-policy/sandbox/sandbox-empty.sub.html b/tests/wpt/tests/content-security-policy/sandbox/sandbox-empty.sub.html
index 47034710203..47c3aa1e365 100644
--- a/tests/wpt/tests/content-security-policy/sandbox/sandbox-empty.sub.html
+++ b/tests/wpt/tests/content-security-policy/sandbox/sandbox-empty.sub.html
@@ -18,7 +18,7 @@
}
-
+
+
+
diff --git a/tests/wpt/tests/content-security-policy/sandbox/sandbox-last-directive-csp.html b/tests/wpt/tests/content-security-policy/sandbox/sandbox-last-directive-csp.html
new file mode 100644
index 00000000000..b4b2cdbe329
--- /dev/null
+++ b/tests/wpt/tests/content-security-policy/sandbox/sandbox-last-directive-csp.html
@@ -0,0 +1,18 @@
+
+