Low firefox Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactlow
DescriptionInformation disclosure in the IP Protection component
ComponentToolkit
Bug ClassLogic Error
Tracker2025849
Fix commit279a692e2f4c (firefox) +35/-46
CISA KEVNot listed
CreditedRintaro Kobayashi
Disclosed2026-05-19

Changed Functions

FunctionChangeNotes
if
toolkit/components/ipprotection/IPPChannelFilter.sys.mjs
modified
add_task
toolkit/components/ipprotection/tests/xpcshell/test_IPPChannelFilter.js
modified
for
toolkit/components/ipprotection/tests/xpcshell/test_IPPChannelFilter.js
modified

Files Changed

  • toolkit/components/ipprotection/IPPChannelFilter.sys.mjs
  • toolkit/components/ipprotection/tests/xpcshell/test_IPPChannelFilter.js
diff --git a/toolkit/components/ipprotection/IPPChannelFilter.sys.mjs b/toolkit/components/ipprotection/IPPChannelFilter.sys.mjs
index 36d41b8c577..24bcf827994 100644
--- a/toolkit/components/ipprotection/IPPChannelFilter.sys.mjs
+++ b/toolkit/components/ipprotection/IPPChannelFilter.sys.mjs
@@ -337,17 +337,16 @@ export class IPPChannelFilter {
       if (!["http", "https"].includes(uri.scheme)) {
         return true;
       }
+      let principal =
+        channel.loadInfo?.loadingPrincipal ||
+        Services.scriptSecurityManager.getChannelURIPrincipal(channel);
 
-      if (IPPChannelFilter.isLocal(uri)) {
+      if (IPPChannelFilter.isLocal(principal)) {
         return true;
       }
 
       const origin = uri.prePath; // scheme://host[:port]
 
-      let principal =
-        channel.loadInfo?.loadingPrincipal ||
-        Services.scriptSecurityManager.getChannelURIPrincipal(channel);
-
       let hasExclusion = lazy.IPPExceptionsManager.hasExclusion(principal);
 
       if (hasExclusion) {
@@ -370,28 +369,12 @@ export class IPPChannelFilter {
     return new MatchPatternSet(patterns, MATCH_PATTERN_OPTIONS);
   }
 
-  static isLocal(uri) {
-    if (Services.io.hostnameIsLocalIPAddress(uri)) {
-      return true;
-    }
-
-    const hostname = uri.host;
-    return (
-      /^(.+\.)?localhost$/.test(hostname) ||
-      /^(.+\.)?localhost6$/.test(hostname) ||
-      /^(.+\.)?localhost.localdomain$/.test(hostname) ||
-      /^(.+\.)?localhost6.localdomain6$/.test(hostname) ||
-      // https://tools.ietf.org/html/rfc2606
-      /\.example$/.test(hostname) ||
-      /\.invalid$/.test(hostname) ||
-      /\.test$/.test(hostname) ||
-      // https://tools.ietf.org/html/rfc8375
-      /^(.+\.)?home\.arpa$/.test(hostname) ||
-      // https://tools.ietf.org/html/rfc6762
-      /\.local$/.test(hostname) ||
-      // Loopback
-      /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(hostname)
-    );
+  /**
+   *
+   * @param {nsIPrincipal} principal
+   */
+  static isLocal(principal) {
+    return principal.isLoopbackHost || principal.isLocalIpAddress;
   }
 
   /**
diff --git a/toolkit/components/ipprotection/tests/xpcshell/test_IPPChannelFilter.js b/toolkit/components/ipprotection/tests/xpcshell/test_IPPChannelFilter.js
index 5eaab390244..bcaeccc2dd6 100644
--- a/toolkit/components/ipprotection/tests/xpcshell/test_IPPChannelFilter.js
+++ b/toolkit/components/ipprotection/tests/xpcshell/test_IPPChannelFilter.js
@@ -555,40 +555,46 @@ add_task(
 );
 
 add_task(async function test_local_connections() {
+  const makePrincipal = url =>
+    Services.scriptSecurityManager.createContentPrincipal(
+      Services.io.newURI(url),
+      {}
+    );
+
   const tests = [
+    // True either LAN or Loopback
+    ["http://[::]", true],
+    ["http://[::1]", true],
+    ["http://[::1]:1234", true],
+    ["http://[::ffff:0:0]", true],
+    ["http://127.0.0.1", true],
+    ["http://127.1.2.3", true],
+    ["http://10.1.2.3", true],
+    ["http://192.168.0.1", true],
+    ["http://169.254.0.1", true],
     ["http://localhost", true],
-    ["http://looocalhost", false],
     ["http://something.localhost", true],
+    // False, anything else
+    ["http://something.test", false],
+    ["http://looocalhost", false],
     ["http://localhost.something", false],
-    ["http://localhost6", true],
+    ["http://localhost6", false],
     ["http://looocalhost6", false],
-    ["http://something.localhost6", true],
+    ["http://something.localhost6", false],
     ["http://localhost6.something", false],
-    ["http://something.example", true],
+    ["http://something.example", false],
     ["http://example.com", false],
-    ["http://something.invalid", true],
+    ["http://something.invalid", false],
     ["http://invalid.com", false],
-    ["http://something.test", true],
     ["http://test.com", false],
-    ["http://127.0.0.1", true],
-    ["http://127.1.2.3", true],
     ["http://128.1.2.3", false],
-    ["http://169.254.0.1", true],
     ["http://169.253.0.1", false],
-    ["http://192.168.0.1", true],
     ["http://193.168.0.1", false],
-    ["http://10.1.2.3", true],
     ["http://11.1.2.3", false],
-    ["http://[::]", true],
-    ["http://[::ffff:0:0]", true],
   ];
 
-  for (const [uri, isLocal] of tests) {
-    Assert.equal(
-      IPPChannelFilter.isLocal(Services.io.newURI(uri)),
-      isLocal,
-      uri
-    );
+  for (const [url, isLocal] of tests) {
+    Assert.equal(IPPChannelFilter.isLocal(makePrincipal(url)), isLocal, url);
   }
 });
 
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/toolkit/components/ipprotection/tests/xpcshell/test_IPPChannelFilter.js b/toolkit/components/ipprotection/tests/xpcshell/test_IPPChannelFilter.js
index 5eaab390244..bcaeccc2dd6 100644
--- a/toolkit/components/ipprotection/tests/xpcshell/test_IPPChannelFilter.js
+++ b/toolkit/components/ipprotection/tests/xpcshell/test_IPPChannelFilter.js
@@ -555,40 +555,46 @@ add_task(
 );
 
 add_task(async function test_local_connections() {
+  const makePrincipal = url =>
+    Services.scriptSecurityManager.createContentPrincipal(
+      Services.io.newURI(url),
+      {}
+    );
+
   const tests = [
+    // True either LAN or Loopback
+    ["http://[::]", true],
+    ["http://[::1]", true],
+    ["http://[::1]:1234", true],
+    ["http://[::ffff:0:0]", true],
+    ["http://127.0.0.1", true],
+    ["http://127.1.2.3", true],
+    ["http://10.1.2.3", true],
+    ["http://192.168.0.1", true],
+    ["http://169.254.0.1", true],
     ["http://localhost", true],
-    ["http://looocalhost", false],
     ["http://something.localhost", true],
+    // False, anything else
+    ["http://something.test", false],
+    ["http://looocalhost", false],
     ["http://localhost.something", false],
-    ["http://localhost6", true],
+    ["http://localhost6", false],
     ["http://looocalhost6", false],
-    ["http://something.localhost6", true],
+    ["http://something.localhost6", false],
     ["http://localhost6.something", false],
-    ["http://something.example", true],
+    ["http://something.example", false],
     ["http://example.com", false],
-    ["http://something.invalid", true],
+    ["http://something.invalid", false],
     ["http://invalid.com", false],
-    ["http://something.test", true],
     ["http://test.com", false],
-    ["http://127.0.0.1", true],
-    ["http://127.1.2.3", true],
     ["http://128.1.2.3", false],
-    ["http://169.254.0.1", true],
     ["http://169.253.0.1", false],
-    ["http://192.168.0.1", true],
     ["http://193.168.0.1", false],
-    ["http://10.1.2.3", true],
     ["http://11.1.2.3", false],
-    ["http://[::]", true],
-    ["http://[::ffff:0:0]", true],
   ];
 
-  for (const [uri, isLocal] of tests) {
-    Assert.equal(
-      IPPChannelFilter.isLocal(Services.io.newURI(uri)),
-      isLocal,
-      uri
-    );
+  for (const [url, isLocal] of tests) {
+    Assert.equal(IPPChannelFilter.isLocal(makePrincipal(url)), isLocal, url);
   }
 });
Loading diff…