Bug#1118231: quickjs: CVE-2025-62490 CVE-2025-62491 CVE-2025-62492 CVE-2025-62493 CVE-2025-62494 CVE-2025-62495 CVE-2025-62496

Salvatore Bonaccorso carnil at debian.org
Fri Oct 17 06:26:13 BST 2025


Source: quickjs
Version: 2025.04.26-1
Severity: important
Tags: security upstream
X-Debbugs-Cc: carnil at debian.org, Debian Security Team <team at security.debian.org>

Hi,

The following vulnerabilities were published for quickjs.

CVE-2025-62490[0]:
| In quickjs, in js_print_object, when printing an array, the function
| first fetches the array length and then loops over it. The issue is,
| printing a value is not side-effect free. An attacker-defined
| callback could run during js_print_value, during which the array
| could get resized and len1 become out of bounds. This results in a
| use-after-free.A second instance occurs in the same function during
| printing of a map or set objects. The code iterates over
| ms->records list, but once again, elements could be removed from the
| list during js_print_value call.


CVE-2025-62491[1]:
| A Use-After-Free (UAF) vulnerability exists in the QuickJS engine's
| standard library when iterating over the global list of unhandled
| rejected promises (ts->rejected_promise_list).    *  The function
| js_std_promise_rejection_check attempts to iterate over the
| rejected_promise_list to report unhandled rejections using a
| standard list loop.     *  The reason for a promise rejection is
| processed inside the loop, including calling js_std_dump_error1(ctx,
| rp->reason).     *  If the promise rejection reason is an Error
| object that defines a custom property getter (e.g., via
| Object.defineProperty), this getter is executed during the error
| dumping process.     *  The malicious custom getter can execute
| JavaScript code that calls catch() on the same rejected promise
| being processed.     *  Calling catch() internally triggers
| js_std_promise_rejection_tracker, which then removes and frees the
| current promise entry (JSRejectedPromiseEntry) from the
| rejected_promise_list.     *  Since the list iteration continues
| using the now-freed memory pointer (el), the subsequent loop access
| results in a Use-After-Free condition.


CVE-2025-62492[2]:
| A vulnerability stemming from floating-point arithmetic precision
| errors exists in the QuickJS engine's implementation of
| TypedArray.prototype.indexOf() when a negative fromIndex argument is
| supplied.    *  The fromIndex argument (read as a double variable,
| $d$) is used to calculate the starting position for the search.
| *  If d is negative, the index is calculated relative to the end of
| the array by adding the array's length (len) to d:    $$d_{new} = d
| + \text{len}$$     *  Due to the inherent limitations of floating-
| point arithmetic, if the negative value $d$ is extremely small
| (e.g., $-1 \times 10^{-20}$), the addition $d + \text{len}$ can
| result in a loss of precision, yielding an outcome that is exactly
| equal to $\text{len}$.     *  The result is then converted to an
| integer index $k$: $k = \text{len}$.     *  The search function
| proceeds to read array elements starting from index $k$. Since valid
| indices are $0$ to $\text{len}-1$, starting the read at index
| $\text{len}$ is one element past the end of the array.   This allows
| an attacker to cause an Out-of-Bounds Read of one element
| immediately following the buffer. While the scope of this read is
| small (one element), it can potentially lead to Information
| Disclosure of adjacent memory contents, depending on the execution
| environment.


CVE-2025-62493[3]:
| A vulnerability exists in the QuickJS engine's BigInt string
| conversion logic (js_bigint_to_string1) due to an incorrect
| calculation of the required number of digits, which in turn leads to
| reading memory past the allocated BigInt structure.    *  The
| function determines the number of characters (n_digits) needed for
| the string representation by calculating:  $$ \\ \text{n\_digits} =
| (\text{n\_bits} + \text{log2\_radix} - 1) / \text{log2\_radix}$$
| $$$$This formula is off-by-one in certain edge cases when
| calculating the necessary memory limbs. For instance, a 127-bit
| BigInt using radix 32 (where $\text{log2\_radix}=5$) is calculated
| to need $\text{n\_digits}=26$.     *  The maximum number of bits
| actually stored is $\text{n\_bits}=127$, which requires only two
| 64-bit limbs ($\text{JS\_LIMB\_BITS}=64$).     *  The conversion
| loop iterates $\text{n\_digits}=26$ times, attempting to read 5 bits
| in each iteration, totaling $26 \times 5 = 130$ bits.     *  In the
| final iterations of the loop, the code attempts to read data that
| spans two limbs:  C    c = (r->tab[pos] >> shift) | (r->tab[pos + 1]
| << (JS_LIMB_BITS - shift));            *  Since the BigInt was only
| allocated two limbs, the read operation for r->tab[pos + 1] becomes
| an Out-of-Bounds Read when pos points to the last valid limb (e.g.,
| $pos=1$).   This vulnerability allows an attacker to cause the
| engine to read and process data from the memory immediately
| following the BigInt buffer. This can lead to Information Disclosure
| of sensitive data stored on the heap adjacent to the BigInt object.


CVE-2025-62494[4]:
| A type confusion vulnerability exists in the handling of the string
| addition (+) operation within the QuickJS engine.    *  The code
| first checks if the left-hand operand is a string.     *  It then
| attempts to convert the right-hand operand to a primitive value
| using JS_ToPrimitiveFree. This conversion can trigger a callback
| (e.g., toString or valueOf).     *  During this callback, an
| attacker can modify the type of the left-hand operand in memory,
| changing it from a string to a different type (e.g., an object or an
| array).     *  The code then proceeds to call
| JS_ConcatStringInPlace, which still treats the modified left-hand
| value as a string.   This mismatch between the assumed type (string)
| and the actual type allows an attacker to control the data structure
| being processed by the concatenation logic, resulting in a type
| confusion condition. This can lead to out-of-bounds memory access,
| potentially resulting in memory corruption and arbitrary code
| execution in the context of the QuickJS runtime.


CVE-2025-62495[5]:
| An integer overflow vulnerability exists in the QuickJS regular
| expression engine (libregexp) due to an inconsistent representation
| of the bytecode buffer size.    *  The regular expression bytecode
| is stored in a DynBuf structure, which correctly uses a
| $\text{size}\_\text{t}$ (an unsigned type, typically 64-bit) for its
| size member.     *  However, several functions, such as
| re_emit_op_u32 and other internal parsing routines, incorrectly cast
| or store this DynBuf $\text{size}\_\text{t}$ value into a signed int
| (typically 32-bit).     *  When a large or complex regular
| expression (such as those generated by a recursive pattern in a
| Proof-of-Concept) causes the bytecode size to exceed $2^{31}$ bytes
| (the maximum positive value for a signed 32-bit integer), the size
| value wraps around, resulting in a negative integer when stored in
| the int variable (Integer Overflow).     *  This negative value is
| subsequently used in offset calculations. For example, within
| functions like re_parse_disjunction, the negative size is used to
| compute an offset (pos) for patching a jump instruction.     *  This
| negative offset is then incorrectly added to the buffer pointer
| (s->byte\_code.buf + pos), leading to an out-of-bounds write on the
| first line of the snippet below:  put_u32(s->byte_code.buf + pos,
| len);


CVE-2025-62496[6]:
| A vulnerability exists in the QuickJS engine's BigInt string parsing
| logic (js_bigint_from_string) when attempting to create a BigInt
| from a string with an excessively large number of digits.  The
| function calculates the necessary number of bits (n_bits) required
| to store the BigInt using the formula:  $$\text{n\_bits} =
| (\text{n\_digits} \times 27 + 7) / 8 \quad (\text{for radix 10})$$
| *  For large input strings (e.g., $79,536,432$ digits or more for
| base 10), the intermediate calculation $(\text{n\_digits} \times 27
| + 7)$ exceeds the maximum value of a standard signed 32-bit integer,
| resulting in an Integer Overflow.     *  The resulting n_bits value
| becomes unexpectedly small or even negative due to this wrap-around.
| *  This flawed n_bits is then used to compute n_limbs, the number of
| memory "limbs" needed for the BigInt object. Since n_bits is too
| small, the calculated n_limbs is also significantly underestimated.
| *  The function proceeds to allocate a JSBigInt object using this
| underestimated n_limbs.     *  When the function later attempts to
| write the actual BigInt data into the allocated object, the small
| buffer size is quickly exceeded, leading to a Heap Out-of-Bounds
| Write as data is written past the end of the allocated r->tab array.


If you fix the vulnerabilities please also make sure to include the
CVE (Common Vulnerabilities & Exposures) ids in your changelog entry.

For further information see:

[0] https://security-tracker.debian.org/tracker/CVE-2025-62490
    https://www.cve.org/CVERecord?id=CVE-2025-62490
[1] https://security-tracker.debian.org/tracker/CVE-2025-62491
    https://www.cve.org/CVERecord?id=CVE-2025-62491
[2] https://security-tracker.debian.org/tracker/CVE-2025-62492
    https://www.cve.org/CVERecord?id=CVE-2025-62492
[3] https://security-tracker.debian.org/tracker/CVE-2025-62493
    https://www.cve.org/CVERecord?id=CVE-2025-62493
[4] https://security-tracker.debian.org/tracker/CVE-2025-62494
    https://www.cve.org/CVERecord?id=CVE-2025-62494
[5] https://security-tracker.debian.org/tracker/CVE-2025-62495
    https://www.cve.org/CVERecord?id=CVE-2025-62495
[6] https://security-tracker.debian.org/tracker/CVE-2025-62496
    https://www.cve.org/CVERecord?id=CVE-2025-62496

Regards,
Salvatore


More information about the Pkg-a11y-devel mailing list