CVE-2026-74954
Overview
Background
- Cache API
- the DOM
Storage: Cache APIthat lets web content (including Service Workers) persistRequest/Responsepairs on disk. - Padding
- extra filler bytes added to a stored
Responsebody 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.
Attack Path
- Prime the cache
Malicious page or Service Worker triggers cross-origin fetches whose opaque
Responses are stored in theCache API. - Measure stored size
The attacker reads the response’s on-disk/quota accounting, observing the padded and rounded size derived from
kMaxRandomNumberandkRoundUpNumber. - Correlate to true length Because the padding windows are small, the observed size maps back to a narrow range of possible real resource lengths.
- 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.
- Infer secret The recovered size distinguishes resource variants (for example logged-in vs logged-out content), disclosing cross-origin information.
Impact Assessment
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.cppdom/fetch/InternalResponse.cpp
Audit Directions
- Size-based side channelsReview 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 secrecyFlag security-relevant constants (especially ones marked as provisional, like the
Bug 1383656XXX comments) whose values determine how much information is masked. - Opaque response storageAudit
Cache APIand Service Worker storage paths for observable metadata (size, timing, existence) that could differentiate cross-origin responses the storing origin may not read.
Patch
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