Moderate firefox Logic Error 🔧 Commit mapped

Overview

Moderate
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionOther issue in the Address Bar component
ComponentToolkit
Bug ClassLogic Error
Tracker2065402
Fix commit2fa06b2cd57b (firefox) +340/-134
CISA KEVNot listed
CreditedMozilla
Disclosed2026-10-13

Changed Functions

FunctionChangeNotes
if
browser/components/urlbar/UrlbarProviderQuickSuggest.sys.mjs
modified
getViewUpdate
browser/components/urlbar/UrlbarProviderQuickSuggest.sys.mjs
modified
switch
browser/components/urlbar/UrlbarProviderQuickSuggest.sys.mjs
modified
if
browser/components/urlbar/UrlbarProvidersManager.sys.mjs
modified
if
browser/components/urlbar/UrlbarUtils.sys.mjs
modified
getViewUpdate
browser/components/urlbar/UrlbarUtils.sys.mjs
modified
getViewUpdateForPayloadItem
browser/components/urlbar/private/FlightStatusSuggestions.sys.mjs
modified
switch
browser/components/urlbar/private/FlightStatusSuggestions.sys.mjs
modified
if
browser/components/urlbar/private/FlightStatusSuggestions.sys.mjs
modified
getViewUpdateForPayloadItem
browser/components/urlbar/private/MarketSuggestions.sys.mjs
modified
if
browser/components/urlbar/private/MarketSuggestions.sys.mjs
modified
getViewUpdateForPayloadItem
browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs
modified
getViewUpdate
browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs
modified
for
browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs
modified
getViewUpdateForPayloadItem
browser/components/urlbar/private/SportsSuggestions.sys.mjs
modified
if
browser/components/urlbar/private/SportsSuggestions.sys.mjs
modified

Files Changed

  • browser/components/urlbar/UrlbarProviderQuickSuggest.sys.mjs
  • browser/components/urlbar/UrlbarProvidersManager.sys.mjs
  • browser/components/urlbar/UrlbarUtils.sys.mjs
  • browser/components/urlbar/private/FlightStatusSuggestions.sys.mjs
  • browser/components/urlbar/private/MarketSuggestions.sys.mjs
  • browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs
  • browser/components/urlbar/private/SportsSuggestions.sys.mjs
  • browser/components/urlbar/private/YelpRealtimeSuggestions.sys.mjs
  • browser/components/urlbar/tests/UrlbarTestUtils.sys.mjs
  • browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_addons.js
  • browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_dynamicSuggestions.js
  • browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_market.js
  • browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_yelp.js
  • browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_sports.js
  • browser/components/urlbar/tests/quicksuggest/unit/head.js
  • browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_addons.js
  • browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_amp.js
  • browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_merino.js
  • browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_scoreMap.js
  • browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_topPicks.js
  • browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_wikipedia.js
  • browser/components/urlbar/tests/unit/head.js
  • browser/components/urlbar/tests/unit/test_UrlbarUtils_getRemoteIconUrl.js
  • toolkit/modules/FaviconUtils.sys.mjs
diff --git a/browser/components/urlbar/UrlbarProviderQuickSuggest.sys.mjs b/browser/components/urlbar/UrlbarProviderQuickSuggest.sys.mjs
index 25b5fee8dc8..7be6822fd82 100644
--- a/browser/components/urlbar/UrlbarProviderQuickSuggest.sys.mjs
+++ b/browser/components/urlbar/UrlbarProviderQuickSuggest.sys.mjs
@@ -2,7 +2,10 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-import { UrlbarProvider } from "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs";
+import {
+  UrlbarProvider,
+  UrlbarUtils,
+} from "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs";
 
 const lazy = {};
 
@@ -89,9 +92,9 @@ export class UrlbarProviderQuickSuggest extends UrlbarProvider {
    *
    * @param {UrlbarQueryContext} queryContext
    * @param {(provider: UrlbarProvider, result: UrlbarResult) => void} addCallback
-   *   Callback invoked by the provider to add a new result.
+   * @param {UrlbarParentController} controller
    */
-  async startQuery(queryContext, addCallback) {
+  async startQuery(queryContext, addCallback, controller) {
     let instance = this.queryInstance;
     let searchString = this._trimmedSearchString;
 
@@ -118,7 +121,7 @@ export class UrlbarProviderQuickSuggest extends UrlbarProvider {
         break;
       }
 
-      let result = await this.#makeResult(queryContext, suggestion);
+      let result = await this.#makeResult(queryContext, suggestion, controller);
       if (instance != this.queryInstance) {
         return;
       }
@@ -304,12 +307,14 @@ export class UrlbarProviderQuickSuggest extends UrlbarProvider {
   /**
    * This is called only for dynamic result types.
    *
-   * @param {UrlbarResult} result The result whose view will be updated.
-   * @returns {object} An object describing the view update.
+   * @param {UrlbarResult} result
+   * @param {UrlbarParentController} controller
+   * @returns {object}
    */
-  getViewUpdate(result) {
+  getViewUpdate(result, controller) {
     return lazy.QuickSuggest.getFeatureByResult(result)?.getViewUpdate?.(
-      result
+      result,
+      controller
     );
   }
 
@@ -349,7 +354,7 @@ export class UrlbarProviderQuickSuggest extends UrlbarProvider {
     return suggestion.provider;
   }
 
-  async #makeResult(queryContext, suggestion) {
+  async #makeResult(queryContext, suggestion, controller) {
     let result = null;
     let feature = lazy.QuickSuggest.getFeatureBySource(suggestion);
     if (!feature) {
@@ -385,8 +390,19 @@ export class UrlbarProviderQuickSuggest extends UrlbarProvider {
     result.payload.telemetryType = this.#getSuggestionTelemetryType(suggestion);
 
     // Handle icons here unless the feature already did.
-    result.payload.icon ||= suggestion.icon;
     result.payload.iconBlob ||= suggestion.icon_blob;
+    result.payload.icon ||= suggestion.icon;
+    if (result.payload.icon) {
+      // Leave the desired size undefined so that the image's intrinsic size is
+      // used and we can keep hardcoded icon sizes in CSS and out of JS. Note
+      // that the image load will fail if it's an SVG without an intrinsic size,
+      // i.e., if it doesn't have a `width` and `height` on its `<svg>`!
+      result.payload.icon = UrlbarUtils.getRemoteIconUrl(
+        result.payload.icon,
+        undefined,
+        controller
+      );
+    }
 
     switch (suggestion.source) {
       case "merino":
diff --git a/browser/components/urlbar/UrlbarProvidersManager.sys.mjs b/browser/components/urlbar/UrlbarProvidersManager.sys.mjs
index e1aac83cb0b..5adfdecdce9 100644
--- a/browser/components/urlbar/UrlbarProvidersManager.sys.mjs
+++ b/browser/components/urlbar/UrlbarProvidersManager.sys.mjs
@@ -980,7 +980,10 @@ export class Query {
     // live in another process.
     if (result.type == lazy.UrlbarShared.RESULT_TYPE.DYNAMIC) {
       result.payload.viewTemplate = provider.getViewTemplate(result);
-      result.payload.viewUpdate = provider.getViewUpdate(result);
+      result.payload.viewUpdate = provider.getViewUpdate(
+        result,
+        this.controller
+      );
     }
     let commands = provider.tryMethod(
       "getResultCommands",
diff --git a/browser/components/urlbar/UrlbarUtils.sys.mjs b/browser/components/urlbar/UrlbarUtils.sys.mjs
index a3eca9cc1e7..69ac2723280 100644
--- a/browser/components/urlbar/UrlbarUtils.sys.mjs
+++ b/browser/components/urlbar/UrlbarUtils.sys.mjs
@@ -301,7 +301,13 @@ export var UrlbarUtils = {
    * protocol, which keeps the decode out of the parent process (bug 2012436).
    *
    * @param {string} iconUrl The URL of the icon.
-   * @param {number} size The desired size of the icon.
+   * @param {number} [size]
+   *   This param is relevant only if `iconUrl` is remote; it's unused
+   *   otherwise. It specifies the desired maximum width and height of the
+   *   decoded image. Pass a falsey value to decode the image at its intrinsic
+   *   size no matter how big it is. Note that SVGs without a `width` and
+   *   `height` on their `<svg>` have no intrinsic size, and a falsey value will
+   *   cause those image loads to fail. See `getMozRemoteImageURL`.
    * @param {UrlbarParentController} [controller]
    *   The controller the query runs on. It supplies the window the icon renders
    *   in, and whether that window is in a content process, which decodes what
@@ -319,23 +325,21 @@ export var UrlbarUtils = {
       !controller?.rendersInContentProcess &&
       !lazy.FaviconUtils.TRUSTED_FAVICON_SCHEMES.includes(scheme)
     ) {
-      if (Services.env.exists("XPCSHELL_TEST_PROFILE_DIR")) {
-        // XPCShell tests don't have a real window, just use fallback values.
-        return lazy.FaviconUtils.getMozRemoteImageURL(iconUrl, {
-          size,
-          stretch: false,
-          colorScheme: "light",
-        });
-      }
-      return lazy.FaviconUtils.getMozRemoteImageURL(iconUrl, {
-        size: Math.floor(size * controller.browserWindow.devicePixelRatio),
+      // XPCShell tests don't have a real window, just use fallback values.
+      let opts = {
         stretch: false,
-        colorScheme: controller.browserWindow.matchMedia(
+        colorScheme: controller?.browserWindow?.matchMedia?.(
           "(prefers-color-scheme: dark)"
         ).matches
           ? "dark"
           : "light",
-      });
+      };
+      if (size) {
+        opts.size = Math.floor(
+          size * (controller?.browserWindow?.devicePixelRatio ?? 1)
+        );
+      }
+      return lazy.FaviconUtils.getMozRemoteImageURL(iconUrl, opts);
     }
     return iconUrl;
   },
@@ -2284,6 +2288,8 @@ export class UrlbarProvider {
    *
    * @param {UrlbarResult} _result
    *   The result whose view will be updated.
+   * @param {UrlbarParentController} _controller
+   *   The controller.
    * @returns {object}
    *   A view update object as described above.  The names of properties are the
    *   the names of elements declared in the view template.  The values of
@@ -2312,7 +2318,7 @@ export class UrlbarProvider {
    *   {string} [textContent]
    *     A string that will be set as `element.textContent`.
    */
-  getViewUpdate(_result) {
+  getViewUpdate(_result, _controller) {
     return null;
   }
 
diff --git a/browser/components/urlbar/private/FlightStatusSuggestions.sys.mjs b/browser/components/urlbar/private/FlightStatusSuggestions.sys.mjs
index b5bd21d6f93..31a93409f56 100644
--- a/browser/components/urlbar/private/FlightStatusSuggestions.sys.mjs
+++ b/browser/components/urlbar/private/FlightStatusSuggestions.sys.mjs
@@ -2,6 +2,8 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+import { UrlbarUtils } from "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs";
+
 import { RealtimeSuggestProvider } from "moz-src:///browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs";
 
 /**
@@ -90,7 +92,7 @@ export class FlightStatusSuggestions extends RealtimeSuggestProvider {
     ];
   }
 
-  getViewUpdateForPayloadItem(item, index) {
+  getViewUpdateForPayloadItem(item, index, controller) {
     let status;
     switch (item.status) {
       case "Scheduled": {
@@ -145,6 +147,20 @@ export class FlightStatusSuggestions extends RealtimeSuggestProvider {
 
     let foregroundImage;
     let backgroundImage;
+
+    let iconUrl;
+    if (item.airline.icon) {
+      // Leave the desired size undefined so that the image's intrinsic size is
+      // used and we can keep hardcoded icon sizes in CSS and out of JS. Note
+      // that the image load will fail if it's an SVG without an intrinsic size,
+      // i.e., if it doesn't have a `width` and `height` on its `<svg>`!
+      iconUrl = UrlbarUtils.getRemoteIconUrl(
+        item.airline.icon,
+        undefined,
+        controller
+      );
+    }
+
     if (status == "inflight") {
       let backgroundImageId =
         item.progress_percent == 100
@@ -161,16 +177,14 @@ export class FlightStatusSuggestions extends RealtimeSuggestProvider {
       };
       foregroundImage = {
         attributes: {
-          src: item.airline.icon,
+          src: iconUrl,
         },
       };
     } else {
       foregroundImage = {
         attributes: {
-          src:
-            item.airline.icon ??
-            "chrome://browser/skin/urlbar/flight-airline.svg",
-          fallback: !item.airline.icon,
+          src: iconUrl ?? "chrome://browser/skin/urlbar/flight-airline.svg",
+          fallback: !iconUrl,
         },
       };
     }
diff --git a/browser/components/urlbar/private/MarketSuggestions.sys.mjs b/browser/components/urlbar/private/MarketSuggestions.sys.mjs
index 4ca2c3fe0ac..44e627bfef2 100644
--- a/browser/components/urlbar/private/MarketSuggestions.sys.mjs
+++ b/browser/components/urlbar/private/MarketSuggestions.sys.mjs
@@ -2,6 +2,8 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+import { UrlbarUtils } from "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs";
+
 import { RealtimeSuggestProvider } from "moz-src:///browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs";
 
 /**
@@ -66,7 +68,7 @@ export class MarketSuggestions extends RealtimeSuggestProvider {
     ];
   }
 
-  getViewUpdateForPayloadItem(item, index) {
+  getViewUpdateForPayloadItem(item, index, controller) {
     let arrowImageUri;
     let changeDescription;
     let changePercent = parseFloat(item.todays_change_perc);
@@ -81,9 +83,19 @@ export class MarketSuggestions extends RealtimeSuggestProvider {
       arrowImageUri = "chrome://browser/skin/urlbar/market-unchanged.svg";
     }
 
-    let imageUri = item.image_url;
+    let imageUri;
     let isImageAnArrow = false;
-    if (!imageUri) {
+    if (item.image_url) {
+      // Leave the desired size undefined so that the image's intrinsic size is
+      // used and we can keep hardcoded icon sizes in CSS and out of JS. Note
+      // that the image load will fail if it's an SVG without an intrinsic size,
+      // i.e., if it doesn't have a `width` and `height` on its `<svg>`!
+      imageUri = UrlbarUtils.getRemoteIconUrl(
+        item.image_url,
+        undefined,
+        controller
+      );
+    } else {
       isImageAnArrow = true;
       imageUri = arrowImageUri;
     }
diff --git a/browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs b/browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs
index b4fec06fe25..d8afa268f0f 100644
--- a/browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs
+++ b/browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs
@@ -45,7 +45,7 @@ export class RealtimeSuggestProvider extends SuggestProvider {
     throw new Error("Trying to access the base class, must be overridden");
   }
 
-  getViewUpdateForPayloadItem(_item, _index) {
+  getViewUpdateForPayloadItem(_item, _index, _controller) {
     throw new Error("Trying to access the base class, must be overridden");
   }
 
@@ -519,7 +519,7 @@ export class RealtimeSuggestProvider extends SuggestProvider {
     ];
   }
 
-  getViewUpdate(result) {
+  getViewUpdate(result, controller) {
     let { items } = result.payload;
     let hasMultipleItems = items.length > 1;
 
@@ -531,7 +531,10 @@ export class RealtimeSuggestProvider extends SuggestProvider {
 
     for (let i = 0; i < items.length; i++) {
       let item = items[i];
-      Object.assign(update, this.getViewUpdateForPayloadItem(item, i));
+      Object.assign(
+        update,
+        this.getViewUpdateForPayloadItem(item, i, controller)
+      );
     }
 
     return update;
diff --git a/browser/components/urlbar/private/SportsSuggestions.sys.mjs b/browser/components/urlbar/private/SportsSuggestions.sys.mjs
index 5022ee55047..cc2b6be235f 100644
--- a/browser/components/urlbar/private/SportsSuggestions.sys.mjs
+++ b/browser/components/urlbar/private/SportsSuggestions.sys.mjs
@@ -2,6 +2,8 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+import { UrlbarUtils } from "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs";
+
 import { RealtimeSuggestProvider } from "moz-src:///browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs";
 
 const lazy = {};
@@ -136,7 +138,7 @@ export class SportsSuggestions extends RealtimeSuggestProvider {
     ];
   }
 
-  getViewUpdateForPayloadItem(item, index) {
+  getViewUpdateForPayloadItem(item, index, controller) {
     let topUpdate =
       stringifiedScore(item.home_team.score) &&
       stringifiedScore(item.away_team.score)
@@ -145,7 +147,7 @@ export class SportsSuggestions extends RealtimeSuggestProvider {
 
     return {
       ...topUpdate,
-      ...this.#viewUpdateImageAndBottom(item, index),
+      ...this.#viewUpdateImageAndBottom(item, index, controller),
       [`item_${index}`]: {
         attributes: {
           "sport-category": item.sport_category,
@@ -186,7 +188,7 @@ export class SportsSuggestions extends RealtimeSuggestProvider {
     };
   }
 
-  #viewUpdateImageAndBottom(item, i) {
+  #viewUpdateImageAndBottom(item, i, controller) {
     // Format the date.
     let date = new Date(item.date);
     let {
@@ -215,16 +217,30 @@ export class SportsSuggestions extends RealtimeSuggestProvider {
     // Create the image update. Start by creating each team's update.
     let imageUpdatesByTeam = ["home", "away"].reduce((memo, team) => {
       let itemKey = `${team}_team`;
-      let icon = item[itemKey]?.icon;
+
+      let iconUrl;
+      if (item[itemKey]?.icon) {
+        // Leave the desired size undefined so that the image's intrinsic size
+        // is used and we can keep hardcoded icon sizes in CSS and out of JS.
+        // Note that the image load will fail if it's an SVG without an
+        // intrinsic size, i.e., if it doesn't have a `width` and `height` on
+        // its `<svg>`!
+        iconUrl = UrlbarUtils.getRemoteIconUrl(
+          item[itemKey].icon,
+          undefined,
+          controller
+        );
+      }
+
       memo[team] = {
         [`image-container-${i}`]: {
           attributes: {
-            "has-team-icon": icon ? "" : null,
+            "has-team-icon": iconUrl ? "" : null,
           },
         },
         [`image-${i}`]: {
           attributes: {
-            src: icon ?? null,
+            src: iconUrl ?? null,
           },
         },
         [`date-chiclet-day-${i}`]: {
diff --git a/browser/components/urlbar/private/YelpRealtimeSuggestions.sys.mjs b/browser/components/urlbar/private/YelpRealtimeSuggestions.sys.mjs
index f5090db976b..782301d31c1 100644
--- a/browser/components/urlbar/private/YelpRealtimeSuggestions.sys.mjs
+++ b/browser/components/urlbar/private/YelpRealtimeSuggestions.sys.mjs
@@ -2,6 +2,8 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+import { UrlbarUtils } from "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs";
+
 import { RealtimeSuggestProvider } from "moz-src:///browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs";
 
... (file diff truncated)
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/browser/components/urlbar/tests/UrlbarTestUtils.sys.mjs b/browser/components/urlbar/tests/UrlbarTestUtils.sys.mjs
index 085d293d8ff..c459a4dded9 100644
--- a/browser/components/urlbar/tests/UrlbarTestUtils.sys.mjs
+++ b/browser/components/urlbar/tests/UrlbarTestUtils.sys.mjs
@@ -2250,6 +2250,79 @@ export class UrlbarInputBaseTestUtils {
     this.#firstDayOfWeekStub.returns(firstDay);
   }
 
+  /**
+   * Returns a `moz-remote-image` URL for the given http(s) URL. In the returned
+   * URL, only the `url` search param will be set. Designed to be used with
+   * `checkImageUrl()`.
+   *
+   * @param {?string} httpUrl
+   *   A bare http(s) (or other remote) URL.
+   * @returns {string}
+   *   A `moz-remote-image` URL with the `url` search param set, or `httpUrl`
+   *   itself if it's falsey.
+   */
+  makeMozRemoteImageUrl(httpUrl) {
+    if (!httpUrl) {
+      return httpUrl;
+    }
+    let url = new URL("moz-remote-image://");
+    url.searchParams.set("url", httpUrl);
+    return url.toString();
+  }
+
+  /**
+   * Asserts that two image/icon URLs are equivalent, taking into account
+   * `moz-remote-image` URLs. This function considers two `moz-remote-image`
+   * URLs equivalent if their `url` search params are equal.
+   *
+   * This function also asserts that the given actual URL is not an http(s) URL
+   * since remote images should never be decoded in the main process.
+   *
+   * @param {string} actualUrl
+   *   The actual URL being checked. Can be `moz-remote-image`, `chrome`,
+   *   `data`, etc. This function will assert that this is not an http(s) URL.
+   * @param {string} expectedUrl
+   *   The expected URL. If the actual URL is expected to be a
+   *   `moz-remote-image` URL, the expected URL must also be a
+   *   `moz-remote-image`, but only their `url` search params are compared.
+   * @param {string} message
+   *   An optional message that will be logged at the start.
+   */
+  checkImageUrl(actualUrl, expectedUrl, message = "") {
+    this.info("Checking image URLs");
+    if (message) {
+      this.info(message);
+    }
+
+    this.info("Actual:   " + JSON.stringify(actualUrl));
+    this.info("Expected: " + JSON.stringify(expectedUrl));
+
+    this.Assert.ok(
+      !actualUrl.startsWith("http"),
+      "Image URLs should never use http(s) (use moz-remote-image instead)"
+    );
+
+    if (
+      !actualUrl.startsWith("moz-remote-image") ||
+      !expectedUrl.startsWith("moz-remote-image")
+    ) {
+      this.Assert.equal(
+        actualUrl,
+        expectedUrl,
+        "One or both of the image URLs are not moz-remote-image, so they should simply be equal"
+      );
+      return;
+    }
+
+    let actualMozRemoteUrl = new URL(actualUrl);
+    let expectedMozRemoteUrl = new URL(expectedUrl);
+    this.Assert.equal(
+      actualMozRemoteUrl.searchParams.get("url"),
+      expectedMozRemoteUrl.searchParams.get("url"),
+      "The inner URLs of the moz-remote-image URLs should match"
+    );
+  }
+
   #firstDayOfWeekStub;
   #urlbar;
   #zonedDateTimeISOStub;
diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_addons.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_addons.js
index a1b3397028e..45faeb664a2 100644
--- a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_addons.js
+++ b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_addons.js
@@ -105,7 +105,10 @@ add_task(async function basic() {
     const row = element.row;
     Assert.ok(!row.hasAttribute("sponsored"));
     const icon = row.querySelector(".urlbarView-favicon");
-    Assert.equal(icon.src, merinoSuggestion.icon);
+    UrlbarTestUtils.checkImageUrl(
+      icon.src,
+      UrlbarTestUtils.makeMozRemoteImageUrl(merinoSuggestion.icon)
+    );
     const title = row.querySelector(".urlbarView-title");
     Assert.equal(title.textContent, merinoSuggestion.title);
     Assert.ok(
diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_dynamicSuggestions.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_dynamicSuggestions.js
index 3d6a0fb58dc..db0fc6ee5bc 100644
--- a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_dynamicSuggestions.js
+++ b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_dynamicSuggestions.js
@@ -242,7 +242,10 @@ function assertUI(row, payload) {
   Assert.equal(titleElement.textContent, payload.title);
 
   const faviconElement = row.querySelector(".urlbarView-favicon");
-  Assert.equal(faviconElement.src, payload.icon);
+  UrlbarTestUtils.checkImageUrl(
+    faviconElement.src,
+    UrlbarTestUtils.makeMozRemoteImageUrl(payload.icon)
+  );
 
   const urlElement = row.querySelector(".urlbarView-url");
   const displayUrl = payload.shouldShowUrl
diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_market.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_market.js
index 114322aeea7..502a69e0e10 100644
--- a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_market.js
+++ b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_market.js
@@ -136,7 +136,7 @@ add_task(async function ui_single() {
   let target = TEST_MERINO_SINGLE[0].custom_details.polygon.values[0];
   assertItemUI(items[0], {
     changeDescription: "down",
-    image: target.image_url,
+    image: UrlbarTestUtils.makeMozRemoteImageUrl(target.image_url),
     isImageAnArrow: false,
     name: target.name,
     todaysChangePerc: target.todays_change_perc,
@@ -336,7 +336,7 @@ function assertItemUI(item, expected) {
   );
 
   let image = item.querySelector(".urlbarView-realtime-image");
-  Assert.equal(image.getAttribute("src"), expected.image, "Image is correct");
+  UrlbarTestUtils.checkImageUrl(image.getAttribute("src"), expected.image);
 
   let name = item.querySelector(".urlbarView-market-name");
   Assert.equal(name.textContent, expected.name, "Name is correct");
diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_yelp.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_yelp.js
index b0b9f702578..7a86ed595b3 100644
--- a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_yelp.js
+++ b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_yelp.js
@@ -153,7 +153,7 @@ add_task(async function ui_single() {
   Assert.equal(items.length, 1);
   let target = TEST_MERINO_SINGLE[0].custom_details.yelp.values[0];
   assertItemUI(items[0], {
-    image: target.image_url,
+    image: UrlbarTestUtils.makeMozRemoteImageUrl(target.image_url),
     title: target.name,
     address: target.address,
     pricing: target.pricing,
@@ -228,7 +228,7 @@ add_task(async function ui_multi() {
     info(`Check the item[${i}]`);
     let target = TEST_MERINO_MULTI[0].custom_details.yelp.values[i];
     assertItemUI(items[i], {
-      image: target.image_url,
+      image: UrlbarTestUtils.makeMozRemoteImageUrl(target.image_url),
       title: target.name,
       address: target.address,
       pricing: target.pricing,
@@ -297,7 +297,7 @@ add_task(async function activate_multi() {
 });
 
 function assertItemUI(item, expected) {
-  Assert.equal(
+  UrlbarTestUtils.checkImageUrl(
     item.querySelector(".urlbarView-realtime-image").src,
     expected.image
   );
diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_sports.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_sports.js
index ff36630ba9c..48f36d848f7 100644
--- a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_sports.js
+++ b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_sports.js
@@ -840,12 +840,22 @@ async function doOneTest({ expectedItems }) {
             "Child element should have expected attribute: " +
               JSON.stringify({ childName, attr })
           );
-          Assert.equal(
-            child.getAttribute(attr),
-            value,
-            "Child element attribute should have expected value: " +
-              JSON.stringify({ childName, attr })
-          );
+
+          if (childNamePrefix.endsWith("image")) {
+            UrlbarTestUtils.checkImageUrl(
+              child.getAttribute(attr),
+              UrlbarTestUtils.makeMozRemoteImageUrl(value),
+              "Child image attribute should have expected value: " +
+                JSON.stringify({ childName, attr })
+            );
+          } else {
+            Assert.equal(
+              child.getAttribute(attr),
+              value,
+              "Child element attribute should have expected value: " +
+                JSON.stringify({ childName, attr })
+            );
+          }
         }
       }
diff --git a/browser/components/urlbar/tests/quicksuggest/unit/head.js b/browser/components/urlbar/tests/quicksuggest/unit/head.js
index 239f3b1c99d..708dab60ec1 100644
--- a/browser/components/urlbar/tests/quicksuggest/unit/head.js
+++ b/browser/components/urlbar/tests/quicksuggest/unit/head.js
@@ -570,7 +570,7 @@ async function doTelemetryTypeTest({ feature, tests }) {
  *     Additional histories that will be passed to PlacesTestUtils.addVisits().
  *   {UrlbarQueryContext} context
  *     The query context that will be passed to check_results().
- *   {object} conditionalPayloadProperties (optional)
+ *   {object} payloadRules (optional)
  *     The properties that will be passed to check_results().
  *   {Array} expected
  *     The expected results that will be passed to check_results().
@@ -616,7 +616,7 @@ async function doResultCheckTest({ env, tests }) {
     nimbus,
     histories,
     context,
-    conditionalPayloadProperties,
+    payloadRules,
     expected,
     merinoSuggestions = null,
   } of tests) {
@@ -646,7 +646,7 @@ async function doResultCheckTest({ env, tests }) {
 
     await check_results({
       context,
-      conditionalPayloadProperties,
+      payloadRules,
       matches: expected,
     });
 
@@ -805,7 +805,7 @@ async function doShowLessFrequentlyTest({
  *
  *   {UrlbarQueryContext} context
  *     The query context that will be passed to check_results().
- *   {object} conditionalPayloadProperties (optional)
+ *   {object} payloadRules (optional)
  *     The properties that will be passed to check_results().
  *   {number} targetIndex
  *     Index of result that will be executed the command.
@@ -831,16 +831,10 @@ async function doDismissTest({ env, tests }) {
   await QuickSuggestTestUtils.forceSync();
 
   // Test
-  for (let {
-    context,
-    conditionalPayloadProperties,
-    targetIndex,
-    before,
-    after,
-  } of tests) {
+  for (let { context, payloadRules, targetIndex, before, after } of tests) {
     await check_results({
       context,
-      conditionalPayloadProperties,
+      payloadRules,
       matches: before.results,
     });
 
@@ -859,7 +853,7 @@ async function doDismissTest({ env, tests }) {
     // Do another search. The result shouldn't be added.
     await check_results({
       context,
-      conditionalPayloadProperties,
+      payloadRules,
       matches: after.results,
     });
diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_addons.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_addons.js
index d8f63f4013f..8cfb1bff3a6 100644
--- a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_addons.js
+++ b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_addons.js
@@ -26,8 +26,8 @@ AddonTestUtils.createAppInfo(
 const MERINO_SUGGESTIONS = [
   {
     provider: "amo",
-    icon: "icon",
     url: "https://example.com/merino-addon",
+    icon: "https://example.com/merino-addon-icon",
     title: "title",
     description: "description",
     custom_details: {
@@ -561,7 +561,7 @@ function makeExpectedResult({
     description: suggestion.description,
     url: suggestion.url,
     originalUrl: suggestion.url,
-    icon: suggestion.icon,
+    icon: UrlbarTestUtils.makeMozRemoteImageUrl(suggestion.icon),
   });
 }
diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_amp.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_amp.js
index 835ad18093c..e809f7491cd 100644
--- a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_amp.js
+++ b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_amp.js
@@ -469,9 +469,9 @@ add_task(async function dedupeAgainstURL_timestamps() {
         ],
         histories,
         context,
-        conditionalPayloadProperties: {
+        payloadRules: {
... (truncated)
Loading diff…