[Security disclosure] Post-mortem: CSVerifier weak validation of the historical block GIndex. User funds remain safe

TL;DR:

A whitehat security researcher identified and reported a vulnerability in CSM’s usage of Beacon block roots for validator withdrawal verification. The researcher communicated the vulnerability to Lido contributors through Lido’s Immunefi program. The vulnerability was mitigated via a combination of off-chain Oracle improvements and a minor modification to CSM v1 on-chain code following a Lido DAO vote. The vulnerability was never exploited, and user and node operator funds were not affected. A permanent long-term fix is planned with the launch of CSM v2 in September.

Summary

A vulnerability in CSM’s usage of Beacon block roots for validator withdrawal verification was identified, reported by a whitehat security researcher, and communicated to Lido contributors in late June through Lido’s Immunefi program. Then, contributors reviewed the vulnerability, confirmed it, and assessed it with a severity of “high”.

The CSM utilizes beacon roots from EIP-4788 to prove validator withdrawal events, with data available only for the last 8,192 blocks (~27 hours) via a circular buffer. If a withdrawal is not proven within that window, the affected CSVerifier contract used the historicalSummaries structure to first verify the root of a historical block and then prove the withdrawal against it.

The processHistoricalWithdrawalProof method in CSVerifier accepted a user-supplied oldBlock.rootGIndex, validating it only by checking that it was a child of GI_HISTORICAL_SUMMARIES.

At the time of development and initial audits, the ability to inject arbitrary data into Consensus Layer (CL) blocks was limited to Ethereum validators, which posed a low risk of manipulation. However, following the Pectra hardfork, EIP-7685 introduced a mechanism that allowed any Execution Layer (EL) address to submit unvalidated data to the CL. This created an opportunity for attackers to populate historicalSummaries with malicious data and reference fake historical roots to forge withdrawal events.

The vulnerability is now fully mitigated via an on-chain CSVerifier contract rotation that removed the processHistoricalWithdrawalProof method entirely. A permanent, more robust fix with the updated processHistoricalWithdrawalProof method is scheduled to be deployed together with CSM v2.

Impact

A malicious actor could leverage EIP-7685 to inject attacker-chosen (pre-computed) bytes32 values into Consensus-Layer blocks and present them as the root of a historical block. This could potentially allow for adding hashes of “fake” blocks into the CL and supplying the corresponding GIndex to CSVerifier (due to a lack of proper user input validation in the processHistoricalWithdrawalProof method). Since any block could be “faked” this way, a malicious actor could prove a “fake” fact (that never actually occurred) of CSM validator withdrawals with a balance below 32 ETH. If reported to CSVerifier, the bond (nominated in stETH) of the corresponding CSM Node Operator could have been penalized and sent to the Burner contract to be burned with the next Accounting Oracle report. In a worst-case scenario where the exploit would have been triggered, and this process had not been interrupted with existing mitigating safeguards (such as the protocol emergency brakes), ~11k stETH of CSM validators-attached bonds could have been burned, although this would result in no profit for the attacker.
According to on-chain data, the processHistoricalWithdrawalProof method was never used in any version of the CSVerifier. CSM Operators were not affected, the vulnerability was never exploited, and is no longer exploitable. No user funds are at risk.

Mitigants and Fixes

  • An interim off-chain mitigation was shipped shortly after disclosure (lowering the exploit impact from High to Medium by preventing stETH bond burn from being burned). The code of the Lido Accounting Oracle was patched, tested, reviewed by an auditor, and shared with Oracle operators who were asked to review the changes and patch their oracles. The patch temporarily disabled burning of funds transferred to the Burner contract, mitigating possible burn of the stETH tokens from the CSM Node Operators’ bond. Oracle operators will switch to the previous stable version of the Accounting Oracle release, as there is now an on-chain mitigation.
  • A pre-CSM 2.0 on-chain mitigation was shipped together with on-chain vote #190, making the exploit no longer applicable. A set of vote items (#11-12) in on-chain vote #190 rotated CSVerifier to an updated version with the processHistoricalWithdrawalProof method removed. Mixbytes reviewed this change in the updated version of the CSM v1 audit report (see MixBytes’s report).
    Note: the method to process historical proofs is currently disabled; a withdrawal being missed for processing is mitigated by a bot monitoring for new withdrawals so that permissionless reports are made within the ~27-hour window.
  • Future-proof on-chain fix for CSM 2.0 (planned). The updated version of the CSVerifier contract with the fixed processHistoricalWithdrawalProof method that removes user input of the historical block GIndex and replaces it with an explicit GIndex calculation on-chain will be included in the scheduled CSM v2 release in September 2025. In addition to the processHistoricalWithdrawalProof fix, the new version of the CSVerifier features a pausability feature via GateSeal.

Acknowledgement

Lido contributors extend their gratitude to the whitehat researcher who, through the Lido × Immunefi bug-bounty program, responsibly disclosed this vulnerability and ensured it was never exploited on mainnet. We also thank Dmitry Zakharov, CTO of MixBytes—engaged in the GRAPPA initiative—for his swift, independent validation of the off-chain hot-fix deployed shortly after disclosure. Finally, we appreciate the Lido Oracle Committee members for their prompt review and deployment of the off-chain mitigation.

Lessons learned

  1. A thorough check should be implemented when checking user inputs in any on-chain methods, especially those related to CL proofs via EIP-4788. Any unnecessary user input should not be present in the smart contract methods.
  2. For every future Lido protocol component that has complex, externally-mutable logic (e.g., beacon-chain roots delivered via EIP-4788/7685), contributors will ship with “defence-in-depth as default”: on-chain derivation of all indices, exhaustive fail-fast guards on user inputs, and emergency-pause circuits baked in.

Key dates

  • 26 June 2025: Initial discovery of the vulnerability via Immunefi report
  • 26 June 2025: Mitigation plan aligned with Lido contributors group
  • 27 June 2025: Temporary off-chain fix reviewed by MixBytes & deployed
  • 27 June 2025: Report confirmed
  • 4 July 2025: Payment made to WH
  • 21 July 2025: Audit report on CSM with the trimmed CSVerifier published.
  • 23 July 2025: Vote #190 started.
  • 1 August 2025: Temporary on-chain fix (CSVerifier rotation to a trimmed version) deployed as part of vote #190 enactment via DG, which was confirmed via the on-chain alerting system
  • 4 August 2025 (tentatively): The temporary off-chain fix will be reverted due to the temporary on-chain fix deployment
  • Sometime in September 2025 (tentatively): A permanent on-chain fix will be released together with CSM v2.

The weakness is now fully neutralized with no user impact. Lido’s Immunefi program proved its effectiveness one more time as an important layer of the overall security process. Last but not least, development practices were strengthened based on the discovered insufficient proof validation.

16 Likes