Medium CVSS 8.8 firefox Input Validation 🔧 Commit mapped

Overview

Medium
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionThe executable file warning did not warn users before opening files with the <code>terminal</code> extension. <br>*This bug only affects Firefox for macOS. Other versions of Firefox are unaffected.*
ComponentToolkit
Bug ClassInput Validation
Tracker1964385
Fix commit46729af4eff5 (firefox) +13/-9
CWECWE-345 (Insufficient authenticity)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
Creditedpwn2car
Disclosed2025-06-24

Background

`kNonBinaryExecutables`
A list of extensions that are executable/dangerous but not PE binaries; its size is declared in ApplicationReputation.h and must match the array literal.
`.terminal` files (macOS)
Apple Terminal configuration documents that, when opened, cause Terminal to run the commands/settings they encode, effectively executing attacker-chosen behavior.

Root Cause Analysis

The download-safety and launch-warning logic in Firefox decides whether to warn the user by consulting fixed lists of dangerous extensions. On macOS, .terminal documents are executable in effect (opening one runs Terminal with embedded configuration/commands), but none of the relevant lists included .terminal. As a result, a downloaded .terminal file was treated as benign: the executable-file warning in ApplicationReputationService did not fire, and nsLocalFile::IsExecutable did not report it as executable, so the user could open it without the authenticity/danger prompt that other executable types trigger.

The patch is purely additive data: .terminal is appended to ApplicationReputationService::kNonBinaryExecutables (with the declared array length bumped from 5 to 6 in the header), to sExecutableExts in nsLocalFileCommon.cpp (with the extern size constants bumped), to the MOZ_WIDGET_COCOA branch of nsLocalFile::IsExecutable, and to the gtest fixture list. There is no logic change — the root cause is an incomplete enumeration of dangerous file types (a missing denylist entry), gated to macOS because the dangerous behavior is Terminal-specific. The advisory’s “insufficient authenticity” (CWE-345) framing describes the user-facing effect (opening executable content without the warning that attests danger); the diff substantiates an input-validation / incomplete-denylist omission rather than any memory-safety defect.

Key insight
The executable/unsafe-download extension lists omitted macOS .terminal files, which execute embedded commands when opened, so Firefox never showed the dangerous-file warning for a genuinely executable file type.

Attack Path

  1. Craft Attacker builds a malicious .terminal document encoding commands/settings that run when opened in Terminal. (macOS only)
  2. Deliver The file is served for download from an attacker-controlled site.
  3. No warning Because .terminal is absent from the executable/denylists, Application Reputation and IsExecutable classify it as a non-executable download, so the usual “this is an executable file” warning is suppressed. (UI:R — user opens the download)
  4. Open The user, not warned, opens the file; macOS launches Terminal with the attacker’s configuration.
  5. Primitive Execution of attacker-chosen Terminal commands with the user’s privileges (high integrity/confidentiality impact per CVSS 8.8).

Impact Assessment

This affects only Firefox for macOS. No elevated privilege is needed; the attacker needs the user to download and open the file (UI:R). The weakness is a suppressed security warning: a genuinely dangerous file type bypassed the executable-download prompt, so a user who trusts the absence of a warning can be led to run attacker commands. The severity depends on user action to open the file, but the resulting primitive is local command execution in the user’s context, which is why the advisory rates confidentiality/integrity high.

Files Changed

  • toolkit/components/reputationservice/ApplicationReputation.cpp
  • toolkit/components/reputationservice/ApplicationReputation.h
  • toolkit/components/reputationservice/test/gtest/TestExecutableLists.cpp
  • xpcom/io/nsLocalFileCommon.cpp
  • xpcom/io/nsLocalFileCommon.h
  • xpcom/io/nsLocalFileUnix.cpp

Audit Directions

  • macOS "open points to execution" document types
    Audit other Apple document formats that indirectly execute (the neighboring .atloc/.fileloc/.ftploc/.inetloc entries) for completeness and any newly-introduced siblings.
  • List consistency
    Verify every dangerous-extension list (ApplicationReputation, sExecutableExts, IsExecutable, Windows kBinaryFileExtensions) stays in sync; mismatched lists are the recurring defect here.
  • Size-constant drift
    Check that the hard-coded array-length externs in nsLocalFileCommon.h cannot silently desynchronize from the literals.
diff --git a/toolkit/components/reputationservice/ApplicationReputation.cpp b/toolkit/components/reputationservice/ApplicationReputation.cpp
index 5c88ff8c686..74577e38699 100644
--- a/toolkit/components/reputationservice/ApplicationReputation.cpp
+++ b/toolkit/components/reputationservice/ApplicationReputation.cpp
@@ -149,6 +149,7 @@ const char* const ApplicationReputationService::kNonBinaryExecutables[] = {
     ".air",
     ".atloc",
     ".ftploc",
+    ".terminal",
     // clang-format on
 };
 
diff --git a/toolkit/components/reputationservice/ApplicationReputation.h b/toolkit/components/reputationservice/ApplicationReputation.h
index 5ea5b825f7a..204adab34fb 100644
--- a/toolkit/components/reputationservice/ApplicationReputation.h
+++ b/toolkit/components/reputationservice/ApplicationReputation.h
@@ -25,7 +25,7 @@ class ApplicationReputationService final
   NS_DECL_NSIAPPLICATIONREPUTATIONSERVICE
 
  public:
-  static const char* const kNonBinaryExecutables[5];
+  static const char* const kNonBinaryExecutables[6];
 #ifdef XP_WIN
   static const char* const kBinaryFileExtensions[184];
 #else
diff --git a/xpcom/io/nsLocalFileCommon.cpp b/xpcom/io/nsLocalFileCommon.cpp
index a09e3715529..b7a3ead0f9a 100644
--- a/xpcom/io/nsLocalFileCommon.cpp
+++ b/xpcom/io/nsLocalFileCommon.cpp
@@ -118,6 +118,7 @@ const char* const sExecutableExts[] = {
   ".settingcontent-ms",
   ".shb",
   ".shs",
+  ".terminal",    // macOS terminal files
   ".url",
   ".vb",
   ".vbe",
diff --git a/xpcom/io/nsLocalFileCommon.h b/xpcom/io/nsLocalFileCommon.h
index cebcb136094..a37b108f891 100644
--- a/xpcom/io/nsLocalFileCommon.h
+++ b/xpcom/io/nsLocalFileCommon.h
@@ -8,9 +8,9 @@
 #define _NS_LOCAL_FILE_COMMON_H_
 
 #ifdef MOZ_ESR
-extern const char* const sExecutableExts[109];
-#else
 extern const char* const sExecutableExts[110];
+#else
+extern const char* const sExecutableExts[111];
 #endif
 
 #endif
diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp
index 26fd67680ce..dd014183113 100644
--- a/xpcom/io/nsLocalFileUnix.cpp
+++ b/xpcom/io/nsLocalFileUnix.cpp
@@ -1962,12 +1962,13 @@ nsLocalFile::IsExecutable(bool* aResult) {
 #endif
         "air",  // Adobe AIR installer
 #ifdef MOZ_WIDGET_COCOA
-        "atloc",    // Can point to other files.
-        "fileloc",  // File location files can be used to point to other
-                    // files.
-        "ftploc",   // Can point to other files.
-        "inetloc",  // Shouldn't be able to do the same, but can, due to
-                    // macOS vulnerabilities.
+        "atloc",     // Can point to other files.
+        "fileloc",   // File location files can be used to point to other
+                     // files.
+        "ftploc",    // Can point to other files.
+        "inetloc",   // Shouldn't be able to do the same, but can, due to
+                     // macOS vulnerabilities.
+        "terminal",  // macOS Terminal app configuration files
 #endif
         "jar"  // java application bundle
     };
diff --git a/toolkit/components/reputationservice/test/gtest/TestExecutableLists.cpp b/toolkit/components/reputationservice/test/gtest/TestExecutableLists.cpp
index 9e19811169d..87d59d42f52 100644
--- a/toolkit/components/reputationservice/test/gtest/TestExecutableLists.cpp
+++ b/toolkit/components/reputationservice/test/gtest/TestExecutableLists.cpp
@@ -241,6 +241,7 @@ static const char* const kTestFileExtensions[] = {
     ".tbz",       // Linux archive (bzip2)
     ".tbz2",      // Linux archive (bzip2)
     ".tcsh",      // Linux shell
+    ".terminal",  // Apple Terminal configuration files
     ".tgz",       // Linux archive (gzip)
     ".torrent",   // Bittorrent
     ".tpz",       // Linux archive (gzip)
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/toolkit/components/reputationservice/test/gtest/TestExecutableLists.cpp b/toolkit/components/reputationservice/test/gtest/TestExecutableLists.cpp
index 9e19811169d..87d59d42f52 100644
--- a/toolkit/components/reputationservice/test/gtest/TestExecutableLists.cpp
+++ b/toolkit/components/reputationservice/test/gtest/TestExecutableLists.cpp
@@ -241,6 +241,7 @@ static const char* const kTestFileExtensions[] = {
     ".tbz",       // Linux archive (bzip2)
     ".tbz2",      // Linux archive (bzip2)
     ".tcsh",      // Linux shell
+    ".terminal",  // Apple Terminal configuration files
     ".tgz",       // Linux archive (gzip)
     ".torrent",   // Bittorrent
     ".tpz",       // Linux archive (gzip)
Loading diff…