Medium firefox Info Disclosure 🔧 Commit mapped

Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionInformation disclosure due to side-channel in the Storage: Cache API component
ComponentDOM
Bug ClassInfo Disclosure
Tracker2025732
Fix commit2eb4d9c5af74 (firefox) +2/-2
CISA KEVNot listed
CreditedTomoya Nakanishi
Disclosed2026-08-18

Background

Cache API
the DOM Storage: Cache API that lets web content (including Service Workers) persist Request/Response pairs on disk.
Padding
extra filler bytes added to a stored Response body so its on-disk footprint does not reveal the resource’s exact byte length.
`kRoundUpNumber`
the granularity (in bytes) to which a cached body’s padded size is rounded up in dom/cache/FileUtils.cpp.
`kMaxRandomNumber`
the upper bound of the random padding amount added to a body size in dom/fetch/InternalResponse.cpp.

Root Cause Analysis

When a Response is stored via the Cache API, Firefox pads the recorded body size to hide the true length of opaque cross-origin resources, but the padding was too coarse and too small: InternalResponse.cpp drew a random pad of at most kMaxRandomNumber (102400) bytes and FileUtils.cpp rounded up to multiples of kRoundUpNumber (20480) bytes. Because these padding windows were narrow relative to real resource sizes, the padded/rounded size still correlated closely with the underlying resource’s actual length, violating the invariant that a cached opaque response must not leak its true size to the storing origin. An attacker could observe the padded size (for example via quota/storage accounting) and, across many cached responses, recover length information about cross-origin resources they are not entitled to read.

The fix widens both windows — raising kMaxRandomNumber to 1048576 and kRoundUpNumber to 131072 — so the padding-induced uncertainty is large enough to mask the real size and break the side channel. This works because the observable stored size now falls into much larger, coarser buckets that many distinct resource lengths map onto, reducing the information leaked per observation.

Key insight
The core mistake was choosing padding constants too small to actually obscure cross-origin resource sizes, so the “padded” size still tracked the true size; the fix simply enlarges the random and round-up padding bounds so distinct resource lengths collapse into far coarser, less-distinguishable size buckets.

Attack Path

  1. Prime the cache Malicious page or Service Worker triggers cross-origin fetches whose opaque Responses are stored in the Cache API.
  2. Measure stored size The attacker reads the response’s on-disk/quota accounting, observing the padded and rounded size derived from kMaxRandomNumber and kRoundUpNumber.
  3. Correlate to true length Because the padding windows are small, the observed size maps back to a narrow range of possible real resource lengths.
  4. Repeat and refine Across multiple cached responses or repeated stores, the attacker averages out the random padding and narrows the estimate of the cross-origin resource’s true size.
  5. Infer secret The recovered size distinguishes resource variants (for example logged-in vs logged-out content), disclosing cross-origin information.

Impact Assessment

An attacker running script in a content process gains a side channel that leaks the approximate byte length of opaque cross-origin resources they cannot otherwise read, enabling cross-site information disclosure. Exploitation requires the ability to cause the target resources to be fetched and stored in the Cache API and to observe storage size accounting, with accuracy improving over repeated observations. Impact is rated moderate: it discloses size-derived information rather than granting memory corruption or direct content read.

Files Changed

  • dom/cache/FileUtils.cpp
  • dom/fetch/InternalResponse.cpp

Audit Directions

  • Size-based side channels
    Review any place where padding, rounding, or quota accounting is meant to hide cross-origin resource sizes and confirm the obfuscation window is large relative to plausible resource sizes.
  • Magic constants guarding secrecy
    Flag security-relevant constants (especially ones marked as provisional, like the Bug 1383656 XXX comments) whose values determine how much information is masked.
  • Opaque response storage
    Audit Cache API and Service Worker storage paths for observable metadata (size, timing, existence) that could differentiate cross-origin responses the storing origin may not read.
diff --git a/dom/cache/FileUtils.cpp b/dom/cache/FileUtils.cpp
index ff556bfc326..298a5773353 100644
--- a/dom/cache/FileUtils.cpp
+++ b/dom/cache/FileUtils.cpp
@@ -43,7 +43,7 @@ namespace {
 
 // Const variable for generate padding size.
 // XXX This will be tweaked to something more meaningful in Bug 1383656.
-const int64_t kRoundUpNumber = 20480;
+const int64_t kRoundUpNumber = 131072;
 
 // At the moment, the encrypted stream block size is assumed to be unchangeable
 // between encrypting and decrypting blobs. This assumptions holds as long as we
diff --git a/dom/fetch/InternalResponse.cpp b/dom/fetch/InternalResponse.cpp
index f75b9597d97..55e0d918ef7 100644
--- a/dom/fetch/InternalResponse.cpp
+++ b/dom/fetch/InternalResponse.cpp
@@ -23,7 +23,7 @@ namespace {
 
 // Const variable for generate padding size
 // XXX This will be tweaked to something more meaningful in Bug 1383656.
-const uint32_t kMaxRandomNumber = 102400;
+const uint32_t kMaxRandomNumber = 1048576;
 
 }  // namespace
 
Loading diff…