Medium CVSS 5.4 firefox Logic Error 🔧 Commit mapped

Overview

Medium
Severity
5.4
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionThe application failed to account for exceptions thrown by the `loadManifestFromFile` method during add-on signature verification. This flaw, triggered by an invalid or unsupported extension manifest, could have caused runtime errors that disrupted the signature validation process. As a result, the enforcement of signature validation for unrelated add-ons may have been bypassed. Signature validation in this context is used to ensure that third-party applications on the user's computer have not tampered with the user's extensions, limiting the impact of this issue.
ComponentToolkit
Bug ClassLogic Error
Tracker1929600
Fix commit14b51a4cdc84 (firefox) +16/-6
CWECWE-347
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N
CISA KEVNot listed
CreditedRob Wu
Disclosed2024-11-26

Background

`XPIDatabase.sys.mjs`
The Firefox add-on manager module that persists installed extension metadata and performs runtime bookkeeping such as signature verification.
`loadManifestFromFile`
An XPIInstall method that parses an extension’s manifest.json from its _sourceBundle on disk, returning add-on details or throwing when the manifest is invalid or unsupported.
`signedState`
A per-add-on field (compared against SIGNEDSTATE_SIGNED) recording the outcome of signature validation, which the manager uses to decide whether to keep an extension enabled.
`adminInstallOnly`
A manifest-derived flag, gated behind Services.policies, indicating an add-on that may only be installed by an administrator via enterprise policy.

Root Cause Analysis

During signature re-verification, the vulnerable code path in XPIDatabase unconditionally awaited XPIExports.XPIInstall.loadManifestFromFile to refresh the adminInstallOnly flag for a signed, policy-controlled add-on. Because an already-installed extension’s manifest.json can become invalid or unsupported over time — for example after backward-incompatible changes between Firefox versions — this call could throw, and the exception was never caught. The unhandled rejection aborted the enclosing verification loop before it finished, violating the invariant that every add-on’s signature is checked and its disabled state updated on each pass.

As a result, signature enforcement for unrelated add-ons queued after the failing one was skipped, so tampering by third-party applications could go undetected.

The fix wraps the loadManifestFromFile call and the subsequent adminInstallOnly assignment in a try/catch, logging a warning via logger.warn and allowing the loop to continue verifying signatures and updating disabled states for the remaining add-ons.

Key insight
The single mistake was performing a throwable manifest reload inside a security-critical verification loop without exception handling, letting one malformed manifest abort validation of every other add-on; the fix isolates that failure with a try/catch so a bad manifest degrades to a logged warning instead of derailing signature enforcement.

Attack Path

  1. Plant a signed add-on with a broken manifest A third-party application on the machine installs or tampers with a legitimately signed extension whose manifest.json is invalid or unsupported, so that loadManifestFromFile will throw when parsed.
  2. Trigger verification On the next signature re-verification pass, XPIDatabase iterates add-ons and reaches the vulnerable block for this signed, policy-eligible add-on.
  3. Force an unhandled exception The unguarded await XPIExports.XPIInstall.loadManifestFromFile(...) rejects, and with no try/catch the rejection propagates out of the loop.
  4. Skip remaining checks The verification routine terminates early, so signature validation and disabled-state updates never run for the add-ons that would have been processed afterward.
  5. Retain a tampered extension An unrelated add-on that was silently modified by third-party software keeps running because its signature was never re-checked.

Impact Assessment

An attacker with local, third-party-application access to the user’s profile gains the ability to suppress signature enforcement for other extensions by installing a single add-on whose manifest reliably fails to parse. This occurs in the browser’s privileged add-on-manager (parent-process) verification path and requires only that a signed, policy-relevant add-on with an invalid manifest be present when verification runs. The result is a moderate integrity loss: tampered or unauthorized extensions may remain enabled without detection.

Files Changed

  • toolkit/mozapps/extensions/internal/XPIDatabase.sys.mjs

Audit Directions

  • Unguarded awaits in verification loops
    Search security-critical iteration (signature, permission, or policy checks) for awaited calls lacking try/catch, where a single throwing element can abort processing of the rest.
  • Throwable manifest/parser reloads
    Audit other callers of loadManifestFromFile and similar disk-backed parsers for assumptions that stored, already-installed data is still valid, since format drift across versions can make previously good manifests throw.
  • Fail-open error handling
    Review paths where an exception silently short-circuits an enforcement pass rather than isolating the failing item, ensuring failures degrade to a logged warning instead of skipping unrelated security checks.
diff --git a/toolkit/mozapps/extensions/internal/XPIDatabase.sys.mjs b/toolkit/mozapps/extensions/internal/XPIDatabase.sys.mjs
index 17219a88b42..b277e418618 100644
--- a/toolkit/mozapps/extensions/internal/XPIDatabase.sys.mjs
+++ b/toolkit/mozapps/extensions/internal/XPIDatabase.sys.mjs
@@ -2228,12 +2228,22 @@ export const XPIDatabase = {
           addon.signedState === lazy.AddonManager.SIGNEDSTATE_SIGNED &&
           Services.policies
         ) {
-          const addonDetailsFromFile =
-            await XPIExports.XPIInstall.loadManifestFromFile(
-              addon._sourceBundle,
-              addon.location
-            );
-          addon.adminInstallOnly = addonDetailsFromFile.adminInstallOnly;
+          // Manifest file for an installed extension can still become
+          // invalid (e.g. due to backward incompatible changes between
+          // Firefox versions).
+          try {
+            const addonDetailsFromFile =
+              await XPIExports.XPIInstall.loadManifestFromFile(
+                addon._sourceBundle,
+                addon.location
+              );
+            addon.adminInstallOnly = addonDetailsFromFile.adminInstallOnly;
+          } catch (err) {
+            // Simply log the error as a warning to be able to check
+            // the signature and potentially update the disabled state
+            // accordingly.
+            logger.warn(`XPI_verifySignature Warning on '${addon.id}': ${err}`);
+          }
         }
 
         if (
Loading diff…