Skip to content

Out-of-bounds write in bccomp() via crafted operand and scale

High
iluuu1994 published GHSA-x692-q9x7-8c3f Jul 30, 2026

Package

ext-bcmath (PHP)

Affected versions

<8.4.24
<8.5.9

Patched versions

8.4.24
8.5.9

Description

A call to bccomp() with attacker-supplied inputs can lead to an out-of-bounds write to either stack or heap memory. The bug occurs in bc_str2num() when the scale truncates a number whose trailing zeros are subsequently trimmed.

/*
* If set the scale manually and it is smaller than the automatically calculated scale,
* adjust it to match the manual setting.
*/
if (str_scale > scale && !auto_scale) {
fractional_end -= str_scale - scale;
str_scale = scale;
/*
* e.g. 123.0001 with scale 2 -> 123.00
* So, remove the trailing 0 again.
*/
if (str_scale > 0) {
const char *fractional_new_end = bc_skip_zero_reverse(fractional_end, fractional_ptr);
str_scale -= fractional_end - fractional_new_end; /* fractional_end >= fractional_new_end */
}
}

str_scale later determines the number of digits after the decimal point in the resulting string.

*num = bc_new_num_nonzeroed(digits, str_scale);

The string is later populated using bc_copy_and_toggle_bcd(nptr, fractional_ptr, fractional_end).

nptr = bc_copy_and_toggle_bcd(nptr, fractional_ptr, fractional_end);

Note that we have shortened the allocated string (str_scale -= fractional_end - fractional_new_end;) but have not adjusted fractional_end itself. Consequently, bc_copy_and_toggle_bcd(nptr, fractional_ptr, fractional_end) will copy the original, untruncated string into a buffer that is too small, leading to an out-of-bounds write.

BCMath uses a small stack-allocated arena for numbers before falling back to heap allocation, enabling both stack and heap corruption, depending on where the buffer is allocated.

The patch adds fractional_end = fractional_new_end; after the zero truncation.

Severity

High

CVE ID

CVE-2026-17544

Weaknesses

Stack-based Buffer Overflow

A stack-based buffer overflow condition is a condition where the buffer being overwritten is allocated on the stack (i.e., is a local variable or, rarely, a parameter to a function). Learn more on MITRE.

Out-of-bounds Write

The product writes data past the end, or before the beginning, of the intended buffer. Learn more on MITRE.

Credits