CVE-2025-54070 Overview
CVE-2025-54070 is an out-of-bounds read vulnerability [CWE-125] in the OpenZeppelin Contracts library, a widely used framework for secure Ethereum smart contract development. The flaw resides in the lastIndexOf(bytes,byte,uint256) function of the Bytes.sol library. Versions 5.2.0 through 5.3.x are affected, and the issue is patched in version 5.4.0.
When the function receives an empty buffer and a pos argument other than type(uint256).max, it can access uninitialized memory outside the buffer bounds. This can produce an invalid index that appears valid to callers, leading to undefined behavior in downstream logic.
Critical Impact
Smart contracts that trust the return value of lastIndexOf without bounds checking may act on out-of-bounds indices, causing unexpected reverts or logic corruption on-chain.
Affected Products
- OpenZeppelin Contracts version 5.2.0
- OpenZeppelin Contracts versions 5.3.0 through 5.3.x
- Any Solidity smart contract importing the vulnerable Bytes.sol library
Discovery Timeline
- 2025-07-17 - CVE-2025-54070 published to NVD
- 2026-06-17 - Last updated in NVD database
Technical Details for CVE-2025-54070
Vulnerability Analysis
The Bytes.sol library exposes helper routines for scanning byte arrays inside Solidity contracts. The lastIndexOf(bytes,byte,uint256) overload searches a buffer backward from a caller-specified position for a target byte. The function is expected to return type(uint256).max (a sentinel meaning "not found") when the buffer is empty.
The patched behavior in version 5.4.0 ensures that empty buffers immediately return the sentinel value regardless of the pos argument. Before the fix, an attacker-controlled pos on an empty buffer caused the function to dereference memory well past the intended array boundary. Any downstream contract that uses the returned index for further memory access, arithmetic, or state transitions inherits the risk.
Root Cause
The root cause is missing input validation on the combination of an empty buffer and a non-sentinel pos value. The function reads memory at offset buffer + 0x20 + pos without verifying that buffer.length > 0. On the Ethereum Virtual Machine (EVM), memory beyond an allocated array is uninitialized scratch space that may hold residue from prior operations in the same transaction.
Attack Vector
An attacker who can influence the pos argument or the buffer passed to lastIndexOf can trigger reads outside the intended bounds. Two outcomes are possible. First, memory access with a very large pos can exhaust gas and revert the transaction, creating a denial-of-service condition. Second, if uninitialized memory at the computed offset happens to match the search byte, the function returns an out-of-bounds index that a naive caller may treat as valid, producing logic errors, unexpected reverts, or state corruption in dependent contract code.
No verified public exploit code is available for this issue. Refer to the OpenZeppelin Security Advisory GHSA-9rcw-c2f9-2j55 for the maintainer's technical description.
Detection Methods for CVE-2025-54070
Indicators of Compromise
- On-chain transactions targeting contracts that call Bytes.lastIndexOf with attacker-influenced pos values against zero-length buffers.
- Unexplained transaction reverts or out-of-gas failures traceable to Bytes.sol library calls.
Detection Strategies
- Audit smart contract source code and dependency manifests (package.json, foundry.toml, remappings.txt) for OpenZeppelin Contracts versions 5.2.0 through 5.3.x.
- Use static analysis tools such as Slither or Semgrep with custom rules that flag calls to lastIndexOf(bytes,byte,uint256) where the return value is used without a != type(uint256).max check.
- Include the vulnerable function signature in software composition analysis (SCA) rulesets to identify affected deployments across CI/CD pipelines.
Monitoring Recommendations
- Instrument development and staging environments with fuzz tests (Foundry forge fuzz, Echidna) that pass empty buffers with varied pos values to any function calling lastIndexOf.
- Monitor blockchain explorers and internal telemetry for repeated reverts against deployed contracts that link to the vulnerable library version.
- Track OpenZeppelin's advisory feed for related follow-on disclosures affecting the Bytes.sol helpers.
How to Mitigate CVE-2025-54070
Immediate Actions Required
- Upgrade OpenZeppelin Contracts to version 5.4.0 or later in all Solidity projects.
- Recompile and redeploy any affected smart contracts after upgrading, since Solidity libraries are compiled into contract bytecode and cannot be patched in place.
- Review all call sites of Bytes.lastIndexOf and add explicit bounds checks on returned indices before further use.
Patch Information
The fix is included in OpenZeppelin Contracts Release v5.4.0. The patched implementation returns type(uint256).max immediately when the input buffer is empty, eliminating the uninitialized memory read. Full technical details are available in OpenZeppelin Security Advisory GHSA-9rcw-c2f9-2j55.
Workarounds
- If immediate upgrade is not possible, wrap calls to lastIndexOf in a guard that returns type(uint256).max when the input buffer length is zero.
- Always validate the returned index against type(uint256).max and against buffer.length before performing any subsequent memory or storage access.
- Restrict external callers from supplying arbitrary pos values to functions that internally call the vulnerable routine.
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

