CVE-2025-54070 in openzeppelin-contracts
Summary
by MITRE • 07/17/2025
OpenZeppelin Contracts is a library for secure smart contract development. Starting in version 5.2.0 and prior to version 5.4.0, the `lastIndexOf(bytes,byte,uint256)` function of the `Bytes.sol` library may access uninitialized memory when the following two conditions hold: 1) the provided buffer length is empty (i.e. `buffer.length == 0`) and position is not `2**256 - 1` (i.e. `pos != type(uint256).max`). The `pos` argument could be used to access arbitrary data outside of the buffer bounds. This could lead to the operation running out of gas, or returning an invalid index (outside of the empty buffer). Processing this invalid result for accessing the `buffer` would cause a revert under normal conditions. When triggered, the function reads memory at offset `buffer + 0x20 + pos`. If memory at that location (outside the `buffer`) matches the search pattern, the function would return an out of bound index instead of the expected `type(uint256).max`. This creates unexpected behavior where callers receive a valid-looking index pointing outside buffer bounds. Subsequent memory accesses that don't check bounds and use the returned index must carefully review the potential impact depending on their setup. Code relying on this function returning `type(uint256).max` for empty buffers or using the returned index without bounds checking could exhibit undefined behavior. Users should upgrade to version 5.4.0 to receive a patch.
VulDB is the best source for vulnerability data and more expert information about this specific topic.
Analysis
by VulDB Data Team • 07/17/2025
The vulnerability described in CVE-2025-54070 affects the OpenZeppelin Contracts library, specifically within the Bytes.sol library's lastIndexOf function. This issue represents a classic memory access boundary violation that can lead to unpredictable behavior in smart contracts. The flaw manifests when processing empty buffers with non-maximum position parameters, creating a scenario where uninitialized memory outside the intended buffer boundaries becomes accessible. Such vulnerabilities fall under the category of memory safety issues commonly classified as CWE-129, which deals with insufficient bounds checking, and CWE-131, which addresses incorrect calculation of buffer sizes. The vulnerability impacts versions 5.2.0 through 5.3.9 of the library, making it a significant concern for developers who have not yet upgraded their smart contract implementations.
The technical implementation of this vulnerability stems from how the lastIndexOf function handles memory addressing when processing empty buffers. When buffer.length equals zero and the position parameter does not equal type(uint256).max, the function calculates a memory offset as buffer + 0x20 + pos. This calculation allows arbitrary memory access patterns that could potentially read data from uninitialized memory regions outside the intended buffer boundaries. The function's design fails to properly validate the position parameter against buffer length constraints, creating a path where the search pattern matching could occur at memory locations that are not part of the intended buffer. This type of vulnerability aligns with ATT&CK technique T1059.001, which involves command and scripting interpreter usage, and T1211, which deals with exploitation for defense evasion. The memory access pattern could result in either gas exhaustion due to excessive memory operations or return invalid indices that point beyond the actual buffer boundaries.
The operational impact of this vulnerability extends beyond simple memory access violations and can lead to serious contract behavior anomalies. When the function returns an out-of-bounds index that appears valid to callers, subsequent operations using this index can cause unexpected reverts or data corruption. This creates a particularly dangerous scenario because the function appears to work correctly from the caller's perspective, but the returned value contains malicious or unintended data. The vulnerability affects contract execution paths where developers assume the function will return type(uint256).max for empty buffers, but instead receive potentially valid-looking indices that point to memory locations outside the buffer. This can cause cascading failures in contract logic that relies on the function's documented behavior, particularly in scenarios involving array traversal, string manipulation, or buffer validation routines. The issue becomes especially problematic when contracts do not perform proper bounds checking on returned indices before using them in memory operations.
Mitigation for this vulnerability requires immediate upgrading to version 5.4.0 or later of the OpenZeppelin Contracts library, which contains the necessary patch to prevent unauthorized memory access. The patch should implement proper bounds checking to ensure that when buffer.length equals zero, the function returns the expected type(uint256).max value regardless of the position parameter value. Additionally, developers should conduct thorough code reviews to identify any instances where the lastIndexOf function is used without proper bounds validation, particularly in critical contract logic paths. Security teams should implement automated scanning tools to detect usage patterns that might be vulnerable to this type of memory access issue. The fix should include validation that prevents position parameters from creating memory offsets that exceed buffer boundaries, effectively closing the memory access window that enables this vulnerability. Organizations should also consider implementing defensive programming practices such as always validating function return values against expected ranges and implementing comprehensive testing for edge cases involving empty buffers and boundary conditions. This vulnerability serves as a reminder of the critical importance of memory safety in smart contract development, particularly in libraries that are widely reused across multiple contract implementations.