Low CVSS 6.5 firefox Logic Error 🔧 Commit mapped

Overview

Low
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactlow
DescriptionRepeated writes to history interface attributes could have been used to cause a Denial of Service condition in the browser. This was addressed by introducing rate-limiting to this API.
ComponentDOM
Bug ClassLogic Error
Tracker1913000
Fix commit795dad3b68cb (firefox) +49/-37
CWECWE-125 (Out-of-bounds read)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H
CISA KEVNot listed
CreditedAndrei Enache
Disclosed2024-10-29

Background

`BrowsingContext`
The docshell-level object representing a browsing context (a top-level page or frame) that owns per-context state, including the counters used to rate limit navigation and history operations.
Rate limiting
A defensive mechanism that caps how many times a web-exposed API can be invoked within a fixed time span, returning an error once the threshold is exceeded to prevent abuse.
`CallerType`
An enum distinguishing CallerType::System (privileged chrome/internal callers) from CallerType::NonSystem (untrusted web content), used to decide whether rate limiting should apply.
History interface
The web-exposed History API (nsHistory, backing window.history) whose attribute and method calls (e.g. pushState, go, scrollRestoration) can trigger session-history mutations.

Root Cause Analysis

Firefox already had a rate limiter, BrowsingContext::CheckLocationChangeRateLimit, that throttled non-system callers of the Location API, but it was named and conceptually scoped to location changes only. Calls originating from the History interface attributes and methods — routed through code such as ChildSHistory::AsyncGo and nsHistory — were not consistently subjected to the same per-BrowsingContext throttle, so untrusted content could invoke history operations in a tight loop without ever hitting a cap. This violated the invariant that all navigation-affecting, web-reachable APIs on a BrowsingContext should share a single enforced rate limit for non-system callers.

The fix generalizes the mechanism by renaming CheckLocationChangeRateLimit to CheckNavigationRateLimit (and the associated counters mLocationChangeRateLimitCount / mLocationChangeRateLimitSpanStart to mNavigationRateLimitCount / mNavigationRateLimitSpanStart, and prefs dom.navigation.locationChangeRateLimit.* to dom.navigation.navigationRateLimit.*), reflecting that the same limiter now governs both Location and History navigation paths. It also threads CallerType into nsHistory::GetScrollRestoration so history-attribute access participates in the caller-aware throttling. Because every navigation entry point now funnels through the unified CheckNavigationRateLimit counter, repeated history writes are counted and rejected with NS_ERROR_DOM_SECURITY_ERR once the limit is reached.

Key insight
The core mistake was treating the rate limiter as location-specific rather than navigation-wide, leaving the History API able to bypass the throttle; the fix renames and re-scopes the check into a single CheckNavigationRateLimit that all navigation and history paths share.

Attack Path

  1. Obtain script execution An attacker gets untrusted JavaScript running in a normal web page, so all calls are classified as CallerType::NonSystem.
  2. Target the unthrottled History API The script repeatedly writes to window.history interface attributes and methods, whose path did not pass through the Location-scoped CheckLocationChangeRateLimit limiter.
  3. Spin a tight loop Because no unified per-BrowsingContext counter gated these history operations, the script issues history writes far faster than any intended cap.
  4. Exhaust resources The unbounded stream of history mutations consumes CPU and session-history processing, degrading or hanging the browser into a Denial of Service condition.

Impact Assessment

An attacker gains a low-severity Denial of Service, degrading responsiveness of the browser from ordinary untrusted web content running in a content process. The only precondition is the ability to execute script in a page (no special privileges), and it exploits the absence of throttling on the History interface rather than any memory-safety flaw.

Changed Functions

FunctionChangeNotes
if
docshell/base/BrowsingContext.cpp
modified
if
dom/base/nsHistory.cpp
modified
for
docshell/test/navigation/test_rate_limit_location_change.html
modified

Files Changed

  • docshell/base/BrowsingContext.cpp
  • docshell/base/BrowsingContext.h
  • docshell/shistory/ChildSHistory.cpp
  • docshell/test/navigation/test_rate_limit_location_change.html
  • dom/base/Location.cpp
  • dom/base/LocationBase.cpp
  • dom/base/nsHistory.cpp
  • dom/base/nsHistory.h
  • dom/chrome-webidl/BrowsingContext.webidl
  • dom/webidl/History.webidl
  • modules/libpref/init/StaticPrefList.yaml
  • remote/shared/RecommendedPreferences.sys.mjs
  • testing/marionette/client/marionette_driver/geckoinstance.py
  • tools/@types/lib.gecko.dom.d.ts

Audit Directions

  • Partial API coverage of a limiter
    Look for security throttles named or scoped for one API surface while sibling APIs that reach the same underlying state (e.g. Location vs History) skip the check.
  • Missing `CallerType` propagation
    Audit web-exposed getters/setters that do not receive or honor CallerType, since privilege-blind entry points can evade non-system rate limits or checks.
  • Per-`BrowsingContext` counters
    Review other per-context rate-limit or quota counters (mNavigationRateLimitCount and analogues) to confirm every reachable caller funnels through the same increment-and-reject logic.
diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp
index cd4d788c654..9b5c8143cb7 100644
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -3830,17 +3830,16 @@ bool BrowsingContext::ShouldUpdateSessionHistory(uint32_t aLoadType) {
           (IsForceReloadType(aLoadType) && IsSubframe()));
 }
 
-nsresult BrowsingContext::CheckLocationChangeRateLimit(CallerType aCallerType) {
+nsresult BrowsingContext::CheckNavigationRateLimit(CallerType aCallerType) {
   // We only rate limit non system callers
   if (aCallerType == CallerType::System) {
     return NS_OK;
   }
 
   // Fetch rate limiting preferences
-  uint32_t limitCount =
-      StaticPrefs::dom_navigation_locationChangeRateLimit_count();
+  uint32_t limitCount = StaticPrefs::dom_navigation_navigationRateLimit_count();
   uint32_t timeSpanSeconds =
-      StaticPrefs::dom_navigation_locationChangeRateLimit_timespan();
+      StaticPrefs::dom_navigation_navigationRateLimit_timespan();
 
   // Disable throttling if either of the preferences is set to 0.
   if (limitCount == 0 || timeSpanSeconds == 0) {
@@ -3849,15 +3848,15 @@ nsresult BrowsingContext::CheckLocationChangeRateLimit(CallerType aCallerType) {
 
   TimeDuration throttleSpan = TimeDuration::FromSeconds(timeSpanSeconds);
 
-  if (mLocationChangeRateLimitSpanStart.IsNull() ||
-      ((TimeStamp::Now() - mLocationChangeRateLimitSpanStart) > throttleSpan)) {
+  if (mNavigationRateLimitSpanStart.IsNull() ||
+      ((TimeStamp::Now() - mNavigationRateLimitSpanStart) > throttleSpan)) {
     // Initial call or timespan exceeded, reset counter and timespan.
-    mLocationChangeRateLimitSpanStart = TimeStamp::Now();
-    mLocationChangeRateLimitCount = 1;
+    mNavigationRateLimitSpanStart = TimeStamp::Now();
+    mNavigationRateLimitCount = 1;
     return NS_OK;
   }
 
-  if (mLocationChangeRateLimitCount >= limitCount) {
+  if (mNavigationRateLimitCount >= limitCount) {
     // Rate limit reached
 
     Document* doc = GetDocument();
@@ -3870,14 +3869,14 @@ nsresult BrowsingContext::CheckLocationChangeRateLimit(CallerType aCallerType) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
-  mLocationChangeRateLimitCount++;
+  mNavigationRateLimitCount++;
   return NS_OK;
 }
 
-void BrowsingContext::ResetLocationChangeRateLimit() {
+void BrowsingContext::ResetNavigationRateLimit() {
   // Resetting the timestamp object will cause the check function to
   // init again and reset the rate limit.
-  mLocationChangeRateLimitSpanStart = TimeStamp();
+  mNavigationRateLimitSpanStart = TimeStamp();
 }
 
 void BrowsingContext::LocationCreated(dom::Location* aLocation) {
diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h
index e566841106c..98a34cab1ff 100644
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -900,13 +900,13 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
 
   // Checks if we reached the rate limit for calls to Location and History API.
   // The rate limit is controlled by the
-  // "dom.navigation.locationChangeRateLimit" prefs.
+  // "dom.navigation.navigationRateLimit" prefs.
   // Rate limit applies per BrowsingContext.
   // Returns NS_OK if we are below the rate limit and increments the counter.
   // Returns NS_ERROR_DOM_SECURITY_ERR if limit is reached.
-  nsresult CheckLocationChangeRateLimit(CallerType aCallerType);
+  nsresult CheckNavigationRateLimit(CallerType aCallerType);
 
-  void ResetLocationChangeRateLimit();
+  void ResetNavigationRateLimit();
 
   mozilla::dom::DisplayMode DisplayMode() { return Top()->GetDisplayMode(); }
 
@@ -1453,9 +1453,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
   nsTArray<std::function<void(uint64_t)>> mDiscardListeners;
 
   // Counter and time span for rate limiting Location and History API calls.
-  // Used by CheckLocationChangeRateLimit. Do not apply cross-process.
-  uint32_t mLocationChangeRateLimitCount;
-  mozilla::TimeStamp mLocationChangeRateLimitSpanStart;
+  // Used by CheckNavigationRateLimit. Do not apply cross-process.
+  uint32_t mNavigationRateLimitCount;
+  mozilla::TimeStamp mNavigationRateLimitSpanStart;
 
   mozilla::LinkedList<dom::Location> mLocations;
 };
diff --git a/docshell/shistory/ChildSHistory.cpp b/docshell/shistory/ChildSHistory.cpp
index 3e3cf09493d..855d7646177 100644
--- a/docshell/shistory/ChildSHistory.cpp
+++ b/docshell/shistory/ChildSHistory.cpp
@@ -177,7 +177,7 @@ void ChildSHistory::AsyncGo(int32_t aOffset, bool aRequireUserInteraction,
   MOZ_LOG(gSHLog, LogLevel::Debug,
           ("ChildSHistory::AsyncGo(%d), current index = %d", aOffset,
            index.value()));
-  nsresult rv = mBrowsingContext->CheckLocationChangeRateLimit(aCallerType);
+  nsresult rv = mBrowsingContext->CheckNavigationRateLimit(aCallerType);
   if (NS_FAILED(rv)) {
     MOZ_LOG(gSHLog, LogLevel::Debug, ("Rejected"));
     aRv.Throw(rv);
diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp
index 9edb9e0b6f8..11603ce493e 100644
--- a/dom/base/Location.cpp
+++ b/dom/base/Location.cpp
@@ -562,7 +562,7 @@ void Location::Reload(bool aForceget, nsIPrincipal& aSubjectPrincipal,
                               ? CallerType::System
                               : CallerType::NonSystem;
 
-  nsresult rv = bc->CheckLocationChangeRateLimit(callerType);
+  nsresult rv = bc->CheckNavigationRateLimit(callerType);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
diff --git a/dom/base/LocationBase.cpp b/dom/base/LocationBase.cpp
index 7ca3cf83a42..94ab819c94c 100644
--- a/dom/base/LocationBase.cpp
+++ b/dom/base/LocationBase.cpp
@@ -128,7 +128,7 @@ void LocationBase::SetURI(nsIURI* aURI, nsIPrincipal& aSubjectPrincipal,
                               ? CallerType::System
                               : CallerType::NonSystem;
 
-  nsresult rv = bc->CheckLocationChangeRateLimit(callerType);
+  nsresult rv = bc->CheckNavigationRateLimit(callerType);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
diff --git a/dom/base/nsHistory.cpp b/dom/base/nsHistory.cpp
index 99994a73ccd..39d2f12df3f 100644
--- a/dom/base/nsHistory.cpp
+++ b/dom/base/nsHistory.cpp
@@ -72,7 +72,8 @@ uint32_t nsHistory::GetLength(ErrorResult& aRv) const {
   return len >= 0 ? len : 0;
 }
 
-ScrollRestoration nsHistory::GetScrollRestoration(mozilla::ErrorResult& aRv) {
+ScrollRestoration nsHistory::GetScrollRestoration(
+    mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aRv) {
   nsCOMPtr<nsPIDOMWindowInner> win(do_QueryReferent(mInnerWindow));
   if (!win || !win->HasActiveDocument() || !win->GetDocShell()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
@@ -88,6 +89,7 @@ ScrollRestoration nsHistory::GetScrollRestoration(mozilla::ErrorResult& aRv) {
 }
 
 void nsHistory::SetScrollRestoration(mozilla::dom::ScrollRestoration aMode,
+                                     mozilla::dom::CallerType aCallerType,
                                      mozilla::ErrorResult& aRv) {
   nsCOMPtr<nsPIDOMWindowInner> win(do_QueryReferent(mInnerWindow));
   if (!win || !win->HasActiveDocument() || !win->GetDocShell()) {
@@ -95,6 +97,15 @@ void nsHistory::SetScrollRestoration(mozilla::dom::ScrollRestoration aMode,
     return;
   }
 
+  BrowsingContext* bc = win->GetBrowsingContext();
+  if (bc) {
+    nsresult rv = bc->CheckNavigationRateLimit(aCallerType);
+    if (NS_FAILED(rv)) {
+      aRv.Throw(rv);
+      return;
+    }
+  }
+
   win->GetDocShell()->SetCurrentScrollRestorationIsManual(
       aMode == mozilla::dom::ScrollRestoration::Manual);
 }
@@ -152,7 +163,7 @@ void nsHistory::Go(int32_t aDelta, nsIPrincipal& aSubjectPrincipal,
                               ? CallerType::System
                               : CallerType::NonSystem;
 
-  // AsyncGo throws if we hit the location change rate limit.
+  // AsyncGo throws if we hit the navigation rate limit.
   session_history->AsyncGo(aDelta, /* aRequireUserInteraction = */ false,
                            userActivation, callerType, aRv);
 }
@@ -237,7 +248,7 @@ void nsHistory::PushOrReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
 
   BrowsingContext* bc = win->GetBrowsingContext();
   if (bc) {
-    nsresult rv = bc->CheckLocationChangeRateLimit(aCallerType);
+    nsresult rv = bc->CheckNavigationRateLimit(aCallerType);
     if (NS_FAILED(rv)) {
       aRv.Throw(rv);
       return;
diff --git a/dom/base/nsHistory.h b/dom/base/nsHistory.h
index 157052fe44c..5f8b7cd1a58 100644
--- a/dom/base/nsHistory.h
+++ b/dom/base/nsHistory.h
@@ -40,8 +40,9 @@ class nsHistory final : public nsISupports, public nsWrapperCache {
 
   uint32_t GetLength(mozilla::ErrorResult& aRv) const;
   mozilla::dom::ScrollRestoration GetScrollRestoration(
-      mozilla::ErrorResult& aRv);
+      mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aRv);
   void SetScrollRestoration(mozilla::dom::ScrollRestoration aMode,
+                            mozilla::dom::CallerType aCallerType,
                             mozilla::ErrorResult& aRv);
   void GetState(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
                 mozilla::ErrorResult& aRv) const;
diff --git a/dom/chrome-webidl/BrowsingContext.webidl b/dom/chrome-webidl/BrowsingContext.webidl
index c63f2a69c90..28e8d8cb9c6 100644
--- a/dom/chrome-webidl/BrowsingContext.webidl
+++ b/dom/chrome-webidl/BrowsingContext.webidl
@@ -275,7 +275,7 @@ interface BrowsingContext {
   readonly attribute ChildSHistory? childSessionHistory;
 
   // Resets the location change rate limit. Used for testing.
-  undefined resetLocationChangeRateLimit();
+  undefined resetNavigationRateLimit();
 
   readonly attribute long childOffset;
 };
diff --git a/dom/webidl/History.webidl b/dom/webidl/History.webidl
index 934214965dc..d0aa7d2c882 100644
--- a/dom/webidl/History.webidl
+++ b/dom/webidl/History.webidl
@@ -17,7 +17,7 @@ enum ScrollRestoration { "auto", "manual" };
 interface History {
   [Throws]
   readonly attribute unsigned long length;
-  [Throws]
+  [Throws, NeedsCallerType]
   attribute ScrollRestoration scrollRestoration;
   [Throws]
   readonly attribute any state;
diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml
index 3094104d81a..14bfebcd2fc 100644
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -3273,13 +3273,13 @@
 
 # Limit of location change caused by content scripts in a time span per
 # BrowsingContext. This includes calls to History and Location APIs.
-- name: dom.navigation.locationChangeRateLimit.count
+- name: dom.navigation.navigationRateLimit.count
   type: uint32_t
   value: 200
   mirror: always
 
 # Time span in seconds for location change rate limit.
-- name: dom.navigation.locationChangeRateLimit.timespan
+- name: dom.navigation.navigationRateLimit.timespan
   type: uint32_t
   value: 10
   mirror: always
diff --git a/remote/shared/RecommendedPreferences.sys.mjs b/remote/shared/RecommendedPreferences.sys.mjs
index 236a7f0e664..480560b8def 100644
--- a/remote/shared/RecommendedPreferences.sys.mjs
+++ b/remote/shared/RecommendedPreferences.sys.mjs
@@ -223,7 +223,7 @@ const COMMON_PREFERENCES = new Map([
   ["dom.max_script_run_time", 0],
 
   // Disable location change rate limitation
-  ["dom.navigation.locationChangeRateLimit.count", 0],
+  ["dom.navigation.navigationRateLimit.count", 0],
 
   // DOM Push
   ["dom.push.connection.enabled", false],
diff --git a/tools/@types/lib.gecko.dom.d.ts b/tools/@types/lib.gecko.dom.d.ts
index 2a3aef627d0..13a8171fe5a 100644
--- a/tools/@types/lib.gecko.dom.d.ts
+++ b/tools/@types/lib.gecko.dom.d.ts
@@ -5067,7 +5067,7 @@ interface BrowsingContext extends LoadContextMixin {
     watchedByDevTools: boolean;
     readonly window: WindowProxy | null;
     getAllBrowsingContextsInSubtree(): BrowsingContext[];
-    resetLocationChangeRateLimit(): void;
+    resetNavigationRateLimit(): void;
     setRDMPaneMaxTouchPoints(maxTouchPoints: number): void;
     setRDMPaneOrientation(type: OrientationType, rotationAngle: number): void;
 }
diff --git a/docshell/test/navigation/test_rate_limit_location_change.html b/docshell/test/navigation/test_rate_limit_location_change.html
index b1b51b92dde..9fefce12af8 100644
--- a/docshell/test/navigation/test_rate_limit_location_change.html
+++ b/docshell/test/navigation/test_rate_limit_location_change.html
@@ -17,8 +17,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
 
   async function setup() {
     await SpecialPowers.pushPrefEnv({set: [
-      ["dom.navigation.locationChangeRateLimit.count", RATE_LIMIT_COUNT],
-      ["dom.navigation.locationChangeRateLimit.timespan", RATE_LIMIT_TIME_SPAN]]});
+      ["dom.navigation.navigationRateLimit.count", RATE_LIMIT_COUNT],
+      ["dom.navigation.navigationRateLimit.timespan", RATE_LIMIT_TIME_SPAN]]});
   }
 
   let inc = 0;
@@ -26,6 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
   const rateLimitedFunctions = (win) => ({
     "history.replaceState": () => win.history.replaceState(null, "test", `${win.location.href}#${inc++}`),
     "history.pushState":  () => win.history.pushState(null, "test", `${win.location.href}#${inc++}`),
+    "history.SetScrollRestoration": () => win.history.scrollRestoration = "auto",
     "history.back": () => win.history.back(),
     "history.forward": () => win.history.forward(),
     "history.go": () => win.history.go(-1),
@@ -53,7 +54,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
     Object.entries(rateLimitedFunctions(win)).forEach(([name, fn]) => {
       // Reset the rate limit for the next run.
       info("Reset rate limit.");
-      SpecialPowers.wrap(win).browsingContext.resetLocationChangeRateLimit();
+      SpecialPowers.wrap(win).browsingContext.resetNavigationRateLimit();
 
       info(`Calling ${name} ${RATE_LIMIT_COUNT} times to reach the rate limit.`);
       for(let i = 0; i< RATE_LIMIT_COUNT; i++) {
@@ -83,7 +84,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
 
     // Cleanup
     win.close();
-    SpecialPowers.wrap(win).browsingContext.resetLocationChangeRateLimit();
+    SpecialPowers.wrap(win).browsingContext.resetNavigationRateLimit();
     SimpleTest.finish();
   }
 
diff --git a/testing/marionette/client/marionette_driver/geckoinstance.py b/testing/marionette/client/marionette_driver/geckoinstance.py
index 1957d77f158..56a69260518 100644
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -83,8 +83,8 @@ class GeckoInstance(object):
         # No slow script dialogs
         "dom.max_chrome_script_run_time": 0,
         "dom.max_script_run_time": 0,
-        # Disable location change rate limitation
-        "dom.navigation.locationChangeRateLimit.count": 0,
+        # Disable navigation change rate limitation
+        "dom.navigation.navigationRateLimit.count": 0,
         # DOM Push
         "dom.push.connection.enabled": False,
         # Screen Orientation API
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/docshell/test/navigation/test_rate_limit_location_change.html b/docshell/test/navigation/test_rate_limit_location_change.html
index b1b51b92dde..9fefce12af8 100644
--- a/docshell/test/navigation/test_rate_limit_location_change.html
+++ b/docshell/test/navigation/test_rate_limit_location_change.html
@@ -17,8 +17,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
 
   async function setup() {
     await SpecialPowers.pushPrefEnv({set: [
-      ["dom.navigation.locationChangeRateLimit.count", RATE_LIMIT_COUNT],
-      ["dom.navigation.locationChangeRateLimit.timespan", RATE_LIMIT_TIME_SPAN]]});
+      ["dom.navigation.navigationRateLimit.count", RATE_LIMIT_COUNT],
+      ["dom.navigation.navigationRateLimit.timespan", RATE_LIMIT_TIME_SPAN]]});
   }
 
   let inc = 0;
@@ -26,6 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
   const rateLimitedFunctions = (win) => ({
     "history.replaceState": () => win.history.replaceState(null, "test", `${win.location.href}#${inc++}`),
     "history.pushState":  () => win.history.pushState(null, "test", `${win.location.href}#${inc++}`),
+    "history.SetScrollRestoration": () => win.history.scrollRestoration = "auto",
     "history.back": () => win.history.back(),
     "history.forward": () => win.history.forward(),
     "history.go": () => win.history.go(-1),
@@ -53,7 +54,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
     Object.entries(rateLimitedFunctions(win)).forEach(([name, fn]) => {
       // Reset the rate limit for the next run.
       info("Reset rate limit.");
-      SpecialPowers.wrap(win).browsingContext.resetLocationChangeRateLimit();
+      SpecialPowers.wrap(win).browsingContext.resetNavigationRateLimit();
 
       info(`Calling ${name} ${RATE_LIMIT_COUNT} times to reach the rate limit.`);
       for(let i = 0; i< RATE_LIMIT_COUNT; i++) {
@@ -83,7 +84,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
 
     // Cleanup
     win.close();
-    SpecialPowers.wrap(win).browsingContext.resetLocationChangeRateLimit();
+    SpecialPowers.wrap(win).browsingContext.resetNavigationRateLimit();
     SimpleTest.finish();
   }
diff --git a/testing/marionette/client/marionette_driver/geckoinstance.py b/testing/marionette/client/marionette_driver/geckoinstance.py
index 1957d77f158..56a69260518 100644
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -83,8 +83,8 @@ class GeckoInstance(object):
         # No slow script dialogs
         "dom.max_chrome_script_run_time": 0,
         "dom.max_script_run_time": 0,
-        # Disable location change rate limitation
-        "dom.navigation.locationChangeRateLimit.count": 0,
+        # Disable navigation change rate limitation
+        "dom.navigation.navigationRateLimit.count": 0,
         # DOM Push
         "dom.push.connection.enabled": False,
         # Screen Orientation API
Loading diff…