A High-Severity WebAssembly Boundary Condition Vulnerability in Firefox: CVE-2025-13016

Author

Stanislav Fort

Date Published

firefox-blog

AISLE discovered a stack buffer overflow in Firefox's WebAssembly engine that evaded detection for six months despite shipping with its own regression test. The vulnerability, CVE-2025-13016, enabled arbitrary code execution through a single line of incorrect pointer arithmetic, affecting over 180 million Firefox users worldwide.

Introduction

For six months, a subtle pointer arithmetic error in Firefox's WebAssembly implementation silently wrote past stack buffers in hundreds of millions of browsers worldwide. The vulnerability, CVE-2025-13016, was particularly insidious: Mozilla had added a regression test alongside the vulnerable code in April 2025, yet the stack buffer overflow went completely undetected until Aisle's autonomous analyzer found it in October 2025.

A single line of template code, mixing uint8_t* and uint16_t* pointers in a std::copy operation, created a memory corruption vulnerability that could allow attackers to execute arbitrary code. With a CVSS score of 7.5 (High), this flaw affected all Firefox versions from 143 through early 145, and Firefox ESR versions before 140.5, potentially exposing over 180 million monthly active users to exploitation.

What makes this discovery particularly striking is the gap between the bug's subtlety and its potential impact. The vulnerable code passed code review, included a test specifically designed to exercise the same code path, and shipped in multiple Firefox releases. Yet it took Aisle's autonomous analyzer to identify what human reviewers and conventional testing missed: a memory safety violation hiding in plain sight within Firefox's WebAssembly garbage collection logic.

The Technical Details

The Vulnerable Code

The vulnerability resides in Firefox's StableWasmArrayObjectElements template class, specifically in how it handles copying inline WebAssembly array data. The issue is located in js/src/wasm/WasmGcObject.h at line 532 (in the vulnerable version).

Here's the problematic code from the original implementation:

C
1template <typename T>
2class MOZ_RAII StableWasmArrayObjectElements {
3 static constexpr size_t MaxInlineElements =
4 WasmArrayObject::maxInlineElementsForElemSize(sizeof(T));
5 Rooted<WasmArrayObject*> array_;
6 T* elements_;
7 mozilla::Maybe<mozilla::Vector<T, MaxInlineElements, SystemAllocPolicy>>
8 ownElements_;
9
10 public:
11 StableWasmArrayObjectElements(JSContext* cx, Handle<WasmArrayObject*> array)
12 : array_(cx, array), elements_(nullptr) {
13 if (array->isDataInline()) {
14 ownElements_.emplace();
15 if (!ownElements_->resize(array->numElements_)) {
16 MOZ_CRASH();
17 }
18 // VULNERABLE CODE:
19 std::copy(array->inlineStorage(),
20 array->inlineStorage() + array->numElements_ * sizeof(T),
21 ownElements_->begin());
22 elements_ = ownElements_->begin();
23 } else {
24 elements_ = reinterpret_cast<T*>(array->data_);
25 }
26 }
27};

Understanding the Bug

The vulnerability manifests in two distinct ways:

1. Buffer Overflow via Incorrect Pointer Arithmetic

The std::copy call uses uint8_t* pointers from inlineStorage() but performs byte arithmetic to calculate the endpoint. However, std::copy interprets all three arguments as having the same type. When the template is instantiated with T = uint16_t, the algorithm copies numElements_ * sizeof(T) elements (not bytes), resulting in writing twice as much data as intended.

For example, with an array of 50 16-bit elements, the code writes 100 uint16_t values instead of 50, overflowing the stack-allocated vector's inline capacity.

2. Wrong Data Source

The inlineStorage() method returns a pointer to the storage area that begins with a DataHeader, not the actual array elements. The code should have used addressOfInlineData() instead, which points to the data after the header. This means the first 8 bytes copied are metadata rather than array contents.

How the Vulnerability is Triggered

The bug becomes exploitable when Firefox's WebAssembly engine needs to create a stable copy of inline array data during garbage collection. This occurs in the Instance::stringFromCharCodeArray function in js/src/wasm/WasmInstance.cpp:

C
1/* static */
2void* Instance::stringFromCharCodeArray(Instance* instance, void* arrayArg,
3 uint32_t arrayStart,
4 uint32_t arrayEnd) {
5 JSContext* cx = instance->cx();
6 RootedAnyRef arrayRef(cx, AnyRef::fromCompiledCode(arrayArg));
7 Rooted<WasmArrayObject*> array(cx, UncheckedCastToArrayI16<true>(arrayRef));
8
9 uint32_t arrayCount = arrayEnd - arrayStart;
10
11 // First attempt with NoGC
12 JSLinearString* string = NewStringCopyN<NoGC, char16_t>(
13 cx, (char16_t*)array->data_ + arrayStart, arrayCount);
14
15 if (!string) {
16 // VULNERABLE PATH: Falls back to stable copy
17 StableWasmArrayObjectElements<uint16_t> stableElements(cx, array);
18 string = NewStringCopyN<CanGC, char16_t>(
19 cx, (char16_t*)stableElements.elements() + arrayStart, arrayCount);
20 // ...
21 }
22}

When the initial NoGC string allocation fails (during memory pressure or GC), the code creates a StableWasmArrayObjectElements instance. This triggers the vulnerable copy operation.

Demonstrating the Vulnerability

The vulnerability could be triggered through WebAssembly code that creates arrays with specific element types and counts, then invokes string conversion operations under memory pressure conditions. When the fast-path NoGC allocation fails, Firefox's fallback mechanism activates the vulnerable code path. With properly sized arrays, the overflow writes past the stack-allocated vector's capacity.

Mozilla's internal testing with memory sanitizers confirmed the stack buffer overflow, showing writes beyond the intended buffer boundaries in the StableWasmArrayObjectElements constructor.

The Fix

Mozilla's Yury Delendik implemented, after our responsible disclosure, a straightforward fix that addresses both issues. The corrected code properly handles type conversions and uses the correct data pointer:

C
1if (array->isDataInline()) {
2 ownElements_.emplace();
3 if (!ownElements_->resize(array->numElements_)) {
4 MOZ_CRASH();
5 }
6 // FIXED CODE:
7 const T* src = array->inlineArrayElements<T>();
8 std::copy(src, src + array->numElements_, ownElements_->begin());
9 elements_ = ownElements_->begin();
10}

The fix introduces the inlineArrayElements<T>() helper method that returns a properly typed pointer to the array data (after the header):

C
1template <typename T>
2T* inlineArrayElements() {
3 return offsetToPointer<T>(offsetOfInlineArrayData());
4}

This ensures that std::copy receives correctly typed pointers and copies exactly numElements_ elements of type T.

Timeline and Disclosure

The vulnerability demonstrates both the challenges of memory-safe programming and the effectiveness of coordinated disclosure:

  • April 7, 2025: Vulnerable code introduced in Firefox via Bug 1956768
  • October 2, 2025: Aisle's autonomous analyzer discovers the vulnerability
  • October 2, 2025: Igor Morgenstern from Aisle reports the issue to Mozilla immediately
  • October 14, 2025: Mozilla security team triages and confirms the vulnerability
  • October 15, 2025: Fix developed and committed to mozilla-central
  • October 16, 2025: Fix verified on nightly builds
  • October 22, 2025: Fix uplifted to Firefox 145 beta and ESR 140.5
  • November 11, 2025: Public disclosure with Firefox 145 and ESR 140.5 releases

From discovery to fix in just 14 days, this timeline showcases the efficiency of modern coordinated vulnerability disclosure. Mozilla recognized the discovery with a substantial security bug bounty, acknowledging both the severity of the vulnerability and the quality of the report.

Impact and Affected Versions

Vulnerability Assessment

The National Vulnerability Database assigned CVE-2025-13016 a CVSS v3.1 score of 7.5 (High) with the vector:

Shell
1CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H

This scoring reflects:

  • Attack Vector (AV:N): Network-based, exploitable via malicious websites
  • Attack Complexity (AC:H): High complexity; requires precise timing to trigger GC during the vulnerable code path
  • Privileges Required (PR:N): No privileges needed
  • User Interaction (UI:R): Requires user to visit a malicious page
  • Scope (S:U): Unchanged; impact limited to Firefox process
  • Confidentiality/Integrity/Availability (C:H/I:H/A:H): High impact on all three

Affected Software

Vulnerable Versions:

  • Firefox versions 143, 144, and 145 (before the fix)
  • Firefox ESR 140.0 through 140.4

Patched Versions:

  • Firefox 145 and later
  • Firefox ESR 140.5 and later

Not Affected:

  • Firefox ESR 115 (older version without WebAssembly GC support)
  • All Firefox versions prior to 143

The vulnerability affected all platforms supported by Firefox: Windows, macOS, Linux, and Android. Given Firefox's substantial user base of over 180 million monthly active users, the potential impact was significant.

How Long Did the Bug Hide?

The vulnerable code was introduced on April 7, 2025, through Mozilla Bug 1956768. Ironically, that same commit added a regression test using oomTest() to verify the code path's correctness. However, the test didn't detect the vulnerability because:

  1. Without AddressSanitizer, stack buffer overflows into reserved inline capacity often remain silent
  2. The test only verified 4 characters of output, missing data corruption beyond that range
  3. The test primarily succeeded via the fast NoGC path, avoiding the vulnerable fallback

The bug lived in Firefox for approximately 6 months before Aisle's analyzer discovered it, spanning Firefox versions 143 through early 145. During this period, the vulnerability was present in multiple Firefox releases used by millions globally.

Broader Ecosystem Impact

Firefox serves as a critical component of the web ecosystem, and vulnerabilities in its WebAssembly engine have cascading effects:

Distribution Channels

Linux distributions rapidly incorporated the security update:

  • Ubuntu: Security advisory for Firefox packages
  • Debian: Updated packages in stable and testing branches
  • Fedora: Fast-tracked security update
  • Arch Linux: Updated within 24 hours of release
  • Red Hat Enterprise Linux: Security advisory RHSA-2025:XXXX

WebAssembly Ecosystem

This vulnerability highlights security challenges in WebAssembly implementations:

  • WebAssembly's low-level memory model requires extreme care in C++ implementations
  • The interaction between garbage collection and memory operations creates subtle attack surfaces
  • Comprehensive testing, including memory sanitizers, is essential for memory-unsafe languages

Mitigation Guidance

For End Users

Immediate Actions:

  1. Update Firefox immediately to version 145 or later (or ESR 140.5+)
  2. Enable automatic updates: Settings → General → Firefox Updates
  3. Restart Firefox after the update to ensure the new version is running

Verification:

  • Navigate to `about:support` in Firefox
  • Confirm "Version" shows 145.0 or higher (or 140.5+ for ESR)

For System Administrators

Enterprise Deployments:

Shell
1# Verify Firefox version across fleet
2firefox --version
3
4# For ESR deployments
5firefox-esr --version

Temporary Mitigation (if immediate patching is not possible):

  • Disable WebAssembly via `about:config`:Set `javascript.options.wasm` to `false` Note: This breaks legitimate WebAssembly applications

However, these mitigations significantly impact functionality. Updating Firefox remains the only complete solution.

The Role of Autonomous Security Analysis

This discovery exemplifies the power of autonomous security analysis. Aisle's analyzer, piloted by researcher Igor Morgenstern, systematically examined Firefox's WebAssembly implementation and identified the boundary condition error without prior knowledge of the code's structure.

Why Automated Analysis Matters

Traditional security testing methods struggle with issues like CVE-2025-13016:

  • Manual code review: The bug hides in template-heavy C++ code with complex type conversions
  • Fuzzing: Requires hitting precise conditions (GC pressure during specific WebAssembly operations)
  • Static analysis: Must reason about template instantiation and pointer arithmetic across type boundaries

Aisle's autonomous analyzer excels at:

  • Systematically exploring complex codebases
  • Understanding semantic relationships between data structures
  • Identifying subtle memory safety violations
  • Building a stack model of code interconnections and flagging issues in the logical design of the system itself

Our analyzer identified the vulnerability and provided detailed analysis that accelerated Mozilla's response and remediation efforts.

Conclusion

CVE-2025-13016 serves as a reminder that even mature, well-tested codebases can harbor critical vulnerabilities. The bug existed in Firefox for six months, passed code review, and even had a regression test added alongside it. Yet it remained undetected until Aisle's autonomous analyzer found it.

We commend Mozilla's security team for their rapid response and thorough remediation. From our initial report to public release, the entire process took just 40 days, demonstrating Mozilla's commitment to user security. The coordinated disclosure process worked as intended, allowing users to receive patches before attackers could develop exploits.

This discovery reinforces Aisle's mission: to secure the world's critical software infrastructure through autonomous security analysis. As software systems grow more complex, autonomous analyzers will play an increasingly vital role in finding vulnerabilities before adversaries do.

Learn More

Interested in Aisle's autonomous security platform? Visit us at aisle.com or reach out to [email protected].

References

Official Mozilla Advisories:

Vulnerability Databases:

Technical Details:


CVE-2025-13016 was discovered by Aisle's autonomous analyzer and reported by Igor Morgenstern. The vulnerability was responsibly disclosed to Mozilla and patched in Firefox 145 and ESR 140.5.