Firefox · Core
CVE-2026-16390
Logic Error in Core
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
isAllowedbrowser/components/enterprisepolicies/helpers/WebsiteFilter.sys.mjs |
modified | |
ifbrowser/components/enterprisepolicies/helpers/WebsiteFilter.sys.mjs |
modified | |
normalizeURLbrowser/components/enterprisepolicies/helpers/WebsiteFilter.sys.mjs |
modified | |
add_taskbrowser/components/enterprisepolicies/tests/xpcshell/test_websitefilter.js |
modified |
Files Changed
browser/components/enterprisepolicies/helpers/WebsiteFilter.sys.mjsbrowser/components/enterprisepolicies/tests/xpcshell/test_websitefilter.jsbrowser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml
Patch
diff --git a/browser/components/enterprisepolicies/helpers/WebsiteFilter.sys.mjs b/browser/components/enterprisepolicies/helpers/WebsiteFilter.sys.mjs
index cda98f60e1c..8b26f43109b 100644
--- a/browser/components/enterprisepolicies/helpers/WebsiteFilter.sys.mjs
+++ b/browser/components/enterprisepolicies/helpers/WebsiteFilter.sys.mjs
@@ -165,14 +165,30 @@ export let WebsiteFilter = {
return this.QueryInterface(iid);
},
isAllowed(url) {
- if (this._blockPatterns?.matches(url.toLowerCase())) {
+ let normalizedURL = this.normalizeURL(url);
+ // A URL we are about to load should always parse, so this is unexpected.
+ // Block it rather than let an unparseable URL skip the filter.
+ if (normalizedURL == null) {
+ return false;
+ }
+ if (this._blockPatterns?.matches(normalizedURL)) {
if (
!this._exceptionsPatterns ||
- !this._exceptionsPatterns.matches(url.toLowerCase())
+ !this._exceptionsPatterns.matches(normalizedURL)
) {
return false;
}
}
return true;
},
+ normalizeURL(url) {
+ let parsed = URL.parse(url);
+ if (!parsed) {
+ return null;
+ }
+ if (parsed.hostname.endsWith(".")) {
+ parsed.hostname = parsed.hostname.replace(/\.+$/, "");
+ }
+ return parsed.href.toLowerCase();
+ },
};
diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_websitefilter.js b/browser/components/enterprisepolicies/tests/xpcshell/test_websitefilter.js
new file mode 100644
index 00000000000..103004c8a82
--- /dev/null
+++ b/browser/components/enterprisepolicies/tests/xpcshell/test_websitefilter.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const { WebsiteFilter } = ChromeUtils.importESModule(
+ "resource:///modules/policies/WebsiteFilter.sys.mjs"
+);
+
+add_task(async function setup() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ WebsiteFilter: {
+ Block: ["*://accounts.firefox.com/*"],
+ },
+ },
+ });
+});
+
+add_task(async function test_host_normalization() {
+ ok(
+ !WebsiteFilter.isAllowed("https://accounts.firefox.com/"),
+ "Bare host should be blocked"
+ );
+ ok(
+ !WebsiteFilter.isAllowed("https://accounts.firefox.com./"),
+ "Trailing-dot host should be blocked"
+ );
+ ok(
+ !WebsiteFilter.isAllowed("https://accounts.firefox.com.../"),
+ "Multiple trailing dots should be blocked"
+ );
+ ok(
+ !WebsiteFilter.isAllowed("https://accounts.firefox.com%2e/"),
+ "Percent-encoded trailing dot should be blocked"
+ );
+ ok(
+ !WebsiteFilter.isAllowed("https://accounts.firefox.com。/"),
+ "Ideographic full-stop (folds to a trailing dot) should be blocked"
+ );
+ ok(
+ WebsiteFilter.isAllowed("https://example.org./"),
+ "Unrelated trailing-dot host should not be blocked"
+ );
+ ok(
+ !WebsiteFilter.isAllowed("not a parseable url"),
+ "Unparseable URL should be blocked"
+ );
+});
diff --git a/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml b/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml
index a5532c4b387..67a25157634 100644
--- a/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml
+++ b/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml
@@ -80,3 +80,5 @@ support-files = ["config_popups_cookies_addons.json"]
["test_telemetry.js"]
["test_webserial.js"]
+
+["test_websitefilter.js"]
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/browser/components/enterprisepolicies/tests/xpcshell/test_websitefilter.js b/browser/components/enterprisepolicies/tests/xpcshell/test_websitefilter.js
new file mode 100644
index 00000000000..103004c8a82
--- /dev/null
+++ b/browser/components/enterprisepolicies/tests/xpcshell/test_websitefilter.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const { WebsiteFilter } = ChromeUtils.importESModule(
+ "resource:///modules/policies/WebsiteFilter.sys.mjs"
+);
+
+add_task(async function setup() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ WebsiteFilter: {
+ Block: ["*://accounts.firefox.com/*"],
+ },
+ },
+ });
+});
+
+add_task(async function test_host_normalization() {
+ ok(
+ !WebsiteFilter.isAllowed("https://accounts.firefox.com/"),
+ "Bare host should be blocked"
+ );
+ ok(
+ !WebsiteFilter.isAllowed("https://accounts.firefox.com./"),
+ "Trailing-dot host should be blocked"
+ );
+ ok(
+ !WebsiteFilter.isAllowed("https://accounts.firefox.com.../"),
+ "Multiple trailing dots should be blocked"
+ );
+ ok(
+ !WebsiteFilter.isAllowed("https://accounts.firefox.com%2e/"),
+ "Percent-encoded trailing dot should be blocked"
+ );
+ ok(
+ !WebsiteFilter.isAllowed("https://accounts.firefox.com。/"),
+ "Ideographic full-stop (folds to a trailing dot) should be blocked"
+ );
+ ok(
+ WebsiteFilter.isAllowed("https://example.org./"),
+ "Unrelated trailing-dot host should not be blocked"
+ );
+ ok(
+ !WebsiteFilter.isAllowed("not a parseable url"),
+ "Unparseable URL should be blocked"
+ );
+});
diff --git a/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml b/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml
index a5532c4b387..67a25157634 100644
--- a/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml
+++ b/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml
@@ -80,3 +80,5 @@ support-files = ["config_popups_cookies_addons.json"]
["test_telemetry.js"]
["test_webserial.js"]
+
+["test_websitefilter.js"]
Loading diff…
References
On This Page