Share
## https://sploitus.com/exploit?id=C8652FC1-B1CE-5903-82CE-973C82381DB9
# CVE-2025-14174 Analysis: ANGLE Metal Staging Buffer Out-of-Bounds Write

> Technical analysis and proof-of-concept for CVE-2025-14174

| | |
|---|---|
| **CVE** | CVE-2025-14174 |
| **Severity** | High |
| **Affected** | iOS (Safari), macOS (Chrome, Chromium, Electron) |
| **Status** | Patched in ANGLE commit [95a32cb](https://chromium.googlesource.com/angle/angle/+/95a32cb) |
| **Credit** | Apple, Google Threat Analysis Group |

---

## Table of Contents

- [Summary](#summary)
- [Affected Platforms](#affected-platforms)
- [Impact](#impact)
- [Root Cause](#root-cause)
- [Trigger Conditions](#trigger-conditions)
- [Technical Analysis](#technical-analysis)
- [Proof of Concept](#proof-of-concept)
- [The Fix](#the-fix)
- [Detection Notes](#detection-notes)
- [Mitigations](#mitigations)
- [References](#references)

---

## Summary

An out-of-bounds (OOB) write vulnerability exists in ANGLE's Metal backend when uploading depth textures via a staging buffer. The staging buffer size is calculated using `GL_UNPACK_IMAGE_HEIGHT` instead of the actual texture height. When `UNPACK_IMAGE_HEIGHT 

CVE-2025-14174 PoC



const gl = document.getElementById('c').getContext('webgl2');
if (!gl) throw new Error('WebGL2 not supported');

const width = 256, height = 256;
const unpackHeight = 16;  // 


```

**Expected result on vulnerable systems:** `gl.getError()` returns `NO_ERROR` despite the OOB write occurring in the GPU process.

---

## The Fix

[ANGLE commit 95a32cb](https://chromium.googlesource.com/angle/angle/+/95a32cb) corrects the staging buffer allocation to use actual texture dimensions:

```cpp
// BEFORE (vulnerable)
ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, pixelsDepthPitch, nullptr, &stagingBuffer));

// AFTER (fixed)
size_t imageSize = pixelsRowPitch * mtlArea.size.height;
ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, imageSize, nullptr, &stagingBuffer));
```

Additionally, `srcBytesPerImage` calculation was fixed for the blit operation:

```cpp
size_t srcBytesPerImage = mtlArea.size.depth > 1 ? pixelsDepthPitch : 0;
```

---

## Detection Notes

This vulnerability is **difficult to detect from JavaScript**:

- Staging buffers are internal Metal resources in the GPU process
- WebGL typically returns `NO_ERROR` even when the bug is triggered
- Metal validation layers may not flag the overflow
- No visible rendering artifacts in most cases
- Requires instrumentation of Metal API calls or GPU memory debugging

---

## Mitigations

| Approach | Description |
|----------|-------------|
| **Update** | Apply platform updates containing the ANGLE fix |
| **Workaround** | Avoid setting `UNPACK_IMAGE_HEIGHT` smaller than actual height for depth textures |
| **Defense-in-depth** | Use fixed-size uploads where `UNPACK_IMAGE_HEIGHT == height` |

---

## References

- **ANGLE Fix:** https://chromium.googlesource.com/angle/angle/+/95a32cb
- **Chromium Bug:** https://issues.chromium.org/issues/466192044
- **Affected Platforms:**
  - iOS: Safari (WebKit uses ANGLE Metal)
  - macOS: Chrome, Chromium, Electron (use ANGLE Metal)

---

## Credits

**Vulnerability Discovery:** Apple, Google Threat Analysis Group

**Technical Analysis:** This writeup documents independent research and reverse engineering of the vulnerability.

---

*Analysis conducted as part of SpiderWebKit security research project.*