Skip to content

Heap buffer overflow in array_merge()

Moderate
bukka published GHSA-h96m-rvf9-jgm2 Dec 18, 2025

Package

No package listed

Affected versions

< 8.1.34
< 8.2.30
< 8.3.29
< 8.4.16
< 8.5.1

Patched versions

8.1.34
8.2.30
8.3.29
8.4.16
8.5.1

Description

The following PHP code triggers a reliable heap buffer overflow:

$arr = range(0, 2**29);
array_merge($arr, $arr, $arr, $arr, $arr, $arr, $arr, $arr);

Or the general case:

$power = 24; // You can choose this number 1 <= $power < 32
$arr = range(0, 2**$power);
array_merge(...array_fill(0, 2**(32-$power), $arr));

This is because packed arrays in array_merge() have an optimization that requires precomputing the count of the elements, done using count += zend_hash_num_elements(Z_ARRVAL_P(arg));. However, this may overflow. Note that even if it didn't, it would cause a DoS because array_init() will trigger a bailout with too large counts.

The code provided is artificial, but I believe this can happen in the real world with for example large sets of JSON data that are then passed to array_merge(). The total count just has to exceed HT_MAX_SIZE to trigger the DoS or the 32-bit limit to trigger the buffer overflow.

Impact

If we were using a memory safe language we would "just" be limited to the DoS, but now we have heap corruption and all the joys of it.
This bug has been in PHP since PHP 7.1.

Workarounds

Prevent a large number of inputs of long arrays to array_merge().

Security impact

As noted the example code is just a PoC exploit trigger.

The JSON file could be crafted and loaded via json_decode that results in a structure like: [array1, array2, array3, ...]. Then the code could use array_merge(array1, array2, array3, ...) from the JSON data. The arrays itself may be relatively small but if the sum of elements exceed the HT_MAX_SIZE bound, the buffer overflow is triggered.

Something like this:

<?php
$array = json_decode(file_get_contents('input.json')); // array of arrays
array_merge(...$array);

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
High
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
Low
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H

CVE ID

CVE-2025-14178

Weaknesses

No CWEs

Credits