Lido partnered with Composable Security to conduct a threat based security review of the Lido Oracle V8 update, covering Staking Router V3 and support for 0x02 withdrawal-type validators.
Basic information
Project type: Liquid staking protocol
Service: Threat based security review, including retest and advisory support.
Results: One high-risk and nine medium-risk vulnerabilities were detected; the high-risk issue and eight medium-risk issues were fixed, one medium acknowledged; six low-risk issues and five recommendations were fixed, implemented, or acknowledged.
About the Lido
Lido is the largest decentralized staking protocol that allows users to stake ETH and receive a liquid staking derivative in return. The project successfully manages over $20B TVL supporting Ethereum growth and security since 2020.
The Lido Oracle project is a daemon that monitors the Lido staking protocol across the Execution and Consensus layers and submits regular update reports to Lido smart contracts. It is responsible for aggregating, verifying, and relaying critical operational data that support the protocol’s decentralized staking mechanism. In this engagement, the Composable Security team focused on changes introduced in version 8 of Lido Oracle, required for Staking Router V3 and support for 0x02 withdrawal-type validators, shifting oracle accounting from fixed per-validator assumptions to validator balance-based calculations.
The subjects of the test were selected files from the Lido repository:
Accounting Oracle: now reports balances at both Staking Module and Node Operator levels, including a new third-phase per-Node Operator balance report for modules supporting 0x02 validators.
Ejector Oracle: substantially rewritten to operate primarily on validator balances, support weighted exit logic, integrate with the Node Operator MetaRegistry, and account for validator consolidations.
Additional scope: support for CSMv3, the new Curated Module V2, expanded oracle reporting for both CSM and CMv2, proactive telemetry on the Hoodi devnet, the Key Delegation Framework, Python 3.14 migration, and related technical-debt cleanup.
Initial Challenges and Constraints:
The audit scope was updated twice during the security review at the Lido team’s request.
The review demanded deep staking knowledge across the new consolidation, balance, and exit-ordering logic introduced for Staking Router V3 and 0x02 withdrawal-type validators.
Objectives:
Perform a tailored threat analysis.
Identify security issues and potential threats both for Lido and their users.
Improve code clarity and optimize code where possible.
Identified threats
As before every audit, thorough threat modeling is performed. The results are made available to the client for joint analysis.
Key assets that require protection:
stETH rate.
Other protocol’s attributes (e.g. bunker mode, rewards distribution).
Data submitted by the report.
Protocols availability.
Threats and potential attackers goals:
Manipulation of the stETH rate.
Submission of invalid balances.
Rewards theft.
Denial of Service (e.g. due to Oracle malfunction).
Potential scenarios to achieve the indicated attacker’s goals:
Calculating CL balances by omitting certain pending deposits from the total.
Mismatch between off-chain and on-chain assumptions.
Inflating validator balances by including pending transfers from sources that will never deliver funds.
Masking negative reward periods through incorrect rebase calculations.
Receiving incorrect validator state from a compromised or desynchronized Consensus Layer node.
Misattributing validators to wrong operators or modules due to stale or incorrect external data.
Encoding mismatch between off-chain and on-chain data formats causing incorrect operator identification.
Overweighting or underweighting staking modules by using point-in-time balance snapshots instead of time-weighted values.
Incorrect estimation of future protocol reserves leading to insufficient validator exits.
Premature exhaustion of per-report limits due to overstated per-validator balance assumptions.
Tampering with performance or reward data through unauthenticated sidecar interfaces.
Lowering performance thresholds by including penalized validators in baseline calculations.
Suboptimal exit ordering allowing certain modules to retain excess stake longer than intended.
Injecting malicious reward distribution data through compromised off-chain storage providers.
Submitting crafted reports using a compromised oracle member key.
Crashing the oracle by triggering on-chain parameter changes that violate off-chain initialization assumptions.
Blocking report completion by causing data parsing failures from format inconsistencies.
Halting report submission through false activation of protective modes.
Aborting reports by creating inconsistent operator weight configurations.
A comprehensive security review outlined 16 vulnerabilities (1 high, 9 medium, 6 low) and 5 additional recommendations.
Key findings:
[High Severity] Missing pending top ups in CL pending balance calculation: top ups accounted for the current report are ignored in the next frame, lowering the CL pending balance.
[Medium Severity] Infinite loop in get_node_operator_weight if the dormant curated module weight branch is enabled.
[Medium Severity] Incorrect slashings ring buffer projection can under-estimate the midterm slashing penalty.
[Medium Severity] Overstated buffered ether allocated for withdrawal finalization.
[Medium Severity] External operator data length mismatch between on-chain and off-chain.
[Medium Severity] Performance Web Server publicly bound by default with no authentication, authorization or rate limiting.
[Medium Severity] Predictable target balance includes pending consolidations whose source can be slashed.
[Medium Severity] Intra-frame CL rebase correction ignores pending top-ups on existing validators.
[Medium Severity] Invalid weights for CMv1 Node Operators.
[Medium Severity] Invalid type of returned value aborts reward processing for the frame.
The Lido team started fixing issues during the audit, and we verified during the retest that the high-risk vulnerability and eight of the nine medium-risk issues were fully removed, with one medium acknowledged. Four findings were independently reported to Composable Security by the Lido team.
Security enhancements:
The high-risk CL pending-balance calculation was fixed as recommended, so pending top-ups to validators already active on the consensus layer are now included in the Oracle’s CL pending balance instead of being dropped in the next frame.
The infinite loop in get_node_operator_weight was fixed by moving the operator-id iterator outside the while loop, so the curated module oracle no longer hangs while paginating node operators.
The slashings ring-buffer projection was fixed by increasing the first obsolete index by one and making the range condition strict, so a slashing in the reference epoch is no longer dropped and the midterm penalty is no longer under-estimated.
The overstated buffered-ether estimate was fixed so the amount allocated for withdrawal finalization is now the withdrawal reserve value rather than the full buffered ether.
The external operator data length mismatch was fixed so the Oracle now assumes the correct 10-byte length for external node-operator data, preventing failed or misdirected ejections.
The predictable-balance inflation was fixed by ignoring a pending consolidation when its source validator is slashed in get_active_lido_validators, so a doomed consolidation is no longer counted toward a target’s predictable balance.
The intra-frame CL rebase correction was fixed so the injected amount is calculated as specified in the documentation, so top-ups between the sampled and reference blocks no longer inflate the rebase used by the Bunker checks.
The invalid CMv1 node-operator weighting was fixed as recommended by replacing the increment with a plain assignment, so each connected CMv1 operator’s weight is set to the CMv2-derived share and exit ordering follows the documented redistribution.
The invalid return-type mismatch was fixed as recommended by building the validator dictionary with plain node-operator id keys, so reward processing no longer aborts when get_bond_curve_id is called.
Knowledge transfer:
The Lido team was highly engaged: they independently reported four findings, asked Composable Security to review a fix for abnormal CL rebase handling (where Composable Security helped design a corrected algorithm to calculate the rebase between two blocks), and maintained very good communication throughout the review.
Client rating
Meet Composable Security
Get throughly tested by the creators of Smart Contract Security Verification Standard