Firefox · Core
CVE-2026-100828
Logic Error in Core
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifbrowser/components/places/content/controller.js |
modified | |
registerCleanupFunctionbrowser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.js |
modified | |
forbrowser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.js |
modified | |
forbrowser/components/places/tests/browser/browser_toolbar_drop_multiple_with_bookmarklet.js |
modified |
Files Changed
browser/components/places/content/controller.jsbrowser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.jsbrowser/components/places/tests/browser/browser_toolbar_drop_multiple_with_bookmarklet.js
Patch
diff --git a/browser/components/places/content/controller.js b/browser/components/places/content/controller.js
index 7773a850727..1faf824a5f1 100644
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -1636,7 +1636,7 @@ var PlacesControllerDragHelper = {
if (
!flavor.startsWith("text/x-moz-place") &&
(validNodes.length > 1 || dropCount > 1) &&
- validNodes.some(n => n.uri?.startsWith("javascript:"))
+ validNodes.some(n => URL.parse(n.uri)?.protocol === "javascript:")
) {
return false;
}
@@ -1728,18 +1728,14 @@ var PlacesControllerDragHelper = {
if (
externalDrag &&
(nodes.length > 1 || dropCount > 1) &&
- nodes.some(n => n.uri?.startsWith("javascript:"))
+ nodes.some(n => URL.parse(n.uri)?.protocol === "javascript:")
) {
throw new Error("Javascript bookmarklet passed with uris");
}
// If a single javascript url is being dropped from the urlbar or an external source,
// show the bookmark dialog as a speedbump protection against malicious cases.
- if (
- nodes.length == 1 &&
- externalDrag &&
- nodes[0].uri?.startsWith("javascript")
- ) {
+ if (nodes.length == 1 && externalDrag) {
let uri;
try {
uri = Services.io.newURI(nodes[0].uri);
@@ -1747,7 +1743,7 @@ var PlacesControllerDragHelper = {
// Invalid uri, we skip this code and the entry will be discarded later.
}
- if (uri) {
+ if (uri?.scheme === "javascript") {
let bookmarkGuid = await PlacesUIUtils.showBookmarkDialog(
{
action: "add",
diff --git a/browser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.js b/browser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.js
index 91e089038b6..8b3e09be1a5 100644
--- a/browser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.js
+++ b/browser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.js
@@ -9,6 +9,7 @@ const sandbox = sinon.createSandbox();
const URL1 = "https://example.com/1/";
const URL2 = "https://example.com/2/";
const BOOKMARKLET_URL = `javascript: (() => {alert('Hello, World!');})();`;
+const BOOKMARKLET_URL_MIXED_CASE = `JavaScript: (() => {})();`;
let bookmarks;
registerCleanupFunction(async function () {
@@ -34,12 +35,18 @@ add_task(async function test() {
Assert.ok(placesItems, "PlacesToolbarItems should not be null");
/**
- * Simulates a drop of a bookmarklet URI onto the bookmarks bar.
+ * Simulates a drop of a bookmarklet URI onto the bookmarks bar and verifies
+ * the speedbump dialog appears.
*
* @param {string} aEffect
* The effect to use for the drop operation: move, copy, or link.
+ * @param {string} aBookmarkletUrl
+ * The bookmarklet URL to be dropped onto the bookmarks bar.
*/
- let simulateDragDrop = async function (aEffect) {
+ let simulateBookmarkletDragDrop = async function (
+ aEffect,
+ aBookmarkletUrl = BOOKMARKLET_URL
+ ) {
info("Simulates drag/drop of a new javascript:URL to the bookmarks");
await withBookmarksDialog(
true,
@@ -47,7 +54,7 @@ add_task(async function test() {
EventUtils.synthesizeDrop(
toolbar,
placesItems,
- [[{ type: "text/x-moz-url", data: BOOKMARKLET_URL }]],
+ [[{ type: "text/x-moz-url", data: aBookmarkletUrl }]],
aEffect,
window
);
@@ -61,11 +68,21 @@ add_task(async function test() {
Assert.equal(
location,
- BOOKMARKLET_URL,
+ aBookmarkletUrl.trim().replace(/^javascript/i, "javascript"),
"Should have opened the ShowBookmarksDialog with the correct bookmarklet url to be bookmarked"
);
}
);
+ };
+
+ for (let effect of ["copy", "link"]) {
+ for (let bookmarkletUrl of [
+ BOOKMARKLET_URL,
+ BOOKMARKLET_URL_MIXED_CASE,
+ ` javascript: (() => {})();`,
+ ]) {
+ await simulateBookmarkletDragDrop(effect, bookmarkletUrl);
+ }
info("Simulates drag/drop of a new URL to the bookmarks");
let spy = sandbox
@@ -81,18 +98,13 @@ add_task(async function test() {
toolbar,
placesItems,
[[{ type: "text/x-moz-url", data: URL1 }]],
- aEffect,
+ effect,
window
);
await promise;
Assert.ok(spy.notCalled, "ShowBookmarksDialog on drop not called for url");
sandbox.restore();
- };
-
- let effects = ["copy", "link"];
- for (let effect of effects) {
- await simulateDragDrop(effect);
}
info("Move of existing bookmark / bookmarklet on toolbar");
diff --git a/browser/components/places/tests/browser/browser_toolbar_drop_multiple_with_bookmarklet.js b/browser/components/places/tests/browser/browser_toolbar_drop_multiple_with_bookmarklet.js
index 729e456ca0a..c4ee0512c98 100644
--- a/browser/components/places/tests/browser/browser_toolbar_drop_multiple_with_bookmarklet.js
+++ b/browser/components/places/tests/browser/browser_toolbar_drop_multiple_with_bookmarklet.js
@@ -18,12 +18,12 @@ add_task(async function test() {
// matter because we will set its data, effect, and mimeType manually.
let placesItems = document.getElementById("PlacesToolbarItems");
Assert.ok(placesItems, "PlacesToolbarItems should not be null");
- let simulateDragDrop = async function (aEffect, aMimeType) {
- let urls = [
- "https://example.com/1/",
- `javascript: (() => {alert('Hello, World!');})();`,
- "https://example.com/2/",
- ];
+ let simulateDragDrop = async function (
+ aEffect,
+ aMimeType,
+ aJsUrl = `javascript: (() => {alert('Hello, World!');})();`
+ ) {
+ let urls = ["https://example.com/1/", aJsUrl, "https://example.com/2/"];
let data = urls.map(spec => spec + "\n" + spec).join("\n");
@@ -43,8 +43,13 @@ add_task(async function test() {
// Simulate a bookmark drop for all of the mime types and effects.
let mimeType = ["text/x-moz-url"];
- let effects = ["copy", "link"];
- for (let effect of effects) {
- await simulateDragDrop(effect, mimeType);
+ for (let effect of ["copy", "link"]) {
+ for (let jsUrl of [
+ `javascript: (() => {alert('Hello, World!');})();`,
+ `JavaScript: (() => {})();`,
+ ` javascript: (() => {})();`,
+ ]) {
+ await simulateDragDrop(effect, mimeType, jsUrl);
+ }
}
});
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/browser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.js b/browser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.js
index 91e089038b6..8b3e09be1a5 100644
--- a/browser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.js
+++ b/browser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.js
@@ -9,6 +9,7 @@ const sandbox = sinon.createSandbox();
const URL1 = "https://example.com/1/";
const URL2 = "https://example.com/2/";
const BOOKMARKLET_URL = `javascript: (() => {alert('Hello, World!');})();`;
+const BOOKMARKLET_URL_MIXED_CASE = `JavaScript: (() => {})();`;
let bookmarks;
registerCleanupFunction(async function () {
@@ -34,12 +35,18 @@ add_task(async function test() {
Assert.ok(placesItems, "PlacesToolbarItems should not be null");
/**
- * Simulates a drop of a bookmarklet URI onto the bookmarks bar.
+ * Simulates a drop of a bookmarklet URI onto the bookmarks bar and verifies
+ * the speedbump dialog appears.
*
* @param {string} aEffect
* The effect to use for the drop operation: move, copy, or link.
+ * @param {string} aBookmarkletUrl
+ * The bookmarklet URL to be dropped onto the bookmarks bar.
*/
- let simulateDragDrop = async function (aEffect) {
+ let simulateBookmarkletDragDrop = async function (
+ aEffect,
+ aBookmarkletUrl = BOOKMARKLET_URL
+ ) {
info("Simulates drag/drop of a new javascript:URL to the bookmarks");
await withBookmarksDialog(
true,
@@ -47,7 +54,7 @@ add_task(async function test() {
EventUtils.synthesizeDrop(
toolbar,
placesItems,
- [[{ type: "text/x-moz-url", data: BOOKMARKLET_URL }]],
+ [[{ type: "text/x-moz-url", data: aBookmarkletUrl }]],
aEffect,
window
);
@@ -61,11 +68,21 @@ add_task(async function test() {
Assert.equal(
location,
- BOOKMARKLET_URL,
+ aBookmarkletUrl.trim().replace(/^javascript/i, "javascript"),
"Should have opened the ShowBookmarksDialog with the correct bookmarklet url to be bookmarked"
);
}
);
+ };
+
+ for (let effect of ["copy", "link"]) {
+ for (let bookmarkletUrl of [
+ BOOKMARKLET_URL,
+ BOOKMARKLET_URL_MIXED_CASE,
+ ` javascript: (() => {})();`,
+ ]) {
+ await simulateBookmarkletDragDrop(effect, bookmarkletUrl);
+ }
info("Simulates drag/drop of a new URL to the bookmarks");
let spy = sandbox
@@ -81,18 +98,13 @@ add_task(async function test() {
toolbar,
placesItems,
[[{ type: "text/x-moz-url", data: URL1 }]],
- aEffect,
+ effect,
window
);
await promise;
Assert.ok(spy.notCalled, "ShowBookmarksDialog on drop not called for url");
sandbox.restore();
- };
-
- let effects = ["copy", "link"];
- for (let effect of effects) {
- await simulateDragDrop(effect);
}
info("Move of existing bookmark / bookmarklet on toolbar");
diff --git a/browser/components/places/tests/browser/browser_toolbar_drop_multiple_with_bookmarklet.js b/browser/components/places/tests/browser/browser_toolbar_drop_multiple_with_bookmarklet.js
index 729e456ca0a..c4ee0512c98 100644
--- a/browser/components/places/tests/browser/browser_toolbar_drop_multiple_with_bookmarklet.js
+++ b/browser/components/places/tests/browser/browser_toolbar_drop_multiple_with_bookmarklet.js
@@ -18,12 +18,12 @@ add_task(async function test() {
// matter because we will set its data, effect, and mimeType manually.
let placesItems = document.getElementById("PlacesToolbarItems");
Assert.ok(placesItems, "PlacesToolbarItems should not be null");
- let simulateDragDrop = async function (aEffect, aMimeType) {
- let urls = [
- "https://example.com/1/",
- `javascript: (() => {alert('Hello, World!');})();`,
- "https://example.com/2/",
- ];
+ let simulateDragDrop = async function (
+ aEffect,
+ aMimeType,
+ aJsUrl = `javascript: (() => {alert('Hello, World!');})();`
+ ) {
+ let urls = ["https://example.com/1/", aJsUrl, "https://example.com/2/"];
let data = urls.map(spec => spec + "\n" + spec).join("\n");
@@ -43,8 +43,13 @@ add_task(async function test() {
// Simulate a bookmark drop for all of the mime types and effects.
let mimeType = ["text/x-moz-url"];
- let effects = ["copy", "link"];
- for (let effect of effects) {
- await simulateDragDrop(effect, mimeType);
+ for (let effect of ["copy", "link"]) {
+ for (let jsUrl of [
+ `javascript: (() => {alert('Hello, World!');})();`,
+ `JavaScript: (() => {})();`,
+ ` javascript: (() => {})();`,
+ ]) {
+ await simulateDragDrop(effect, mimeType, jsUrl);
+ }
}
});
Loading diff…
References
On This Page