{"id":1195,"date":"2025-10-27T12:51:33","date_gmt":"2025-10-27T10:51:33","guid":{"rendered":"https:\/\/ackee.xyz\/blog\/?p=1195"},"modified":"2025-10-27T12:53:06","modified_gmt":"2025-10-27T10:53:06","slug":"lido-triggerable-withdrawals-audit-summary","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/lido-triggerable-withdrawals-audit-summary\/","title":{"rendered":"Lido Triggerable Withdrawals Audit Summary"},"content":{"rendered":"<p><a href=\"https:\/\/lido.fi\/\" target=\"_blank\" rel=\"noopener\">Lido<\/a> is a decentralized liquid staking protocol for Ethereum. Triggerable withdrawals is a new feature based on the <a href=\"https:\/\/eips.ethereum.org\/EIPS\/eip-7002\" target=\"_blank\" rel=\"noopener\">EIP-7002<\/a> standard that allows for the ejection of validators previously deposited through the Lido protocol.<\/p>\n<p>The primary purpose of triggerable withdrawals is to allow the Lido DAO to withdraw funds locked in a validator when the node operator refuses to submit a withdrawal request. This functionality became available after <a href=\"https:\/\/eips.ethereum.org\/EIPS\/eip-7002\" target=\"_blank\" rel=\"noopener\">EIP-7002<\/a> was implemented on mainnet.<\/p>\n<p>Withdrawal triggering is permissionless; however, users must provide data whose hash matches one already submitted by Easy Track or trigger exits once the Oracle has provided the report data.<\/p>\n<hr \/>\n<p>Lido engaged <a href=\"https:\/\/ackee.xyz\" target=\"_blank\" rel=\"noopener\">Ackee Blockchain Security<\/a> to perform a security review of Lido Triggerable Withdrawals with a total time donation of 38 engineering days in a period between June 5 and July 14, 2025. 10 engineering days were allocated to manually-guided fuzzing using <a href=\"https:\/\/getwake.io\" target=\"_blank\" rel=\"noopener\">Wake<\/a>.<\/p>\n<p>Lido then engaged Ackee Blockchain Security to perform a fix review of the findings from the previous revision. The review was performed between July 23 and July 25, 2025 and no new findings were discovered.<\/p>\n<p>Lido engaged Ackee Blockchain Security to perform a third review, this time of changes made since the previous revision with a total time donation of 0.5 engineering days in a period between September 8 and September 16, 2025 and no new findings were discovered.<\/p>\n<h2><span style=\"font-weight: 400;\">METHODOLOGY<\/span><\/h2>\n<p>We began our review by implementing and executing manually-guided differential fuzz tests in <a href=\"https:\/\/getwake.io\" target=\"_blank\" rel=\"noopener\">Wake<\/a> to verify the correctness of the new functionalities and to ensure the changes do not break existing invariants. Fuzzing was conducted with contracts forked from mainnet and relevant contracts upgraded to the latest version. This ensured full compatibility with the mainnet deployment. 2 staking modules were used to test the triggerable withdrawals functionality \u2013 <a href=\"https:\/\/docs.lido.fi\/contracts\/node-operators-registry\/\" target=\"_blank\" rel=\"noopener\">Node Operators Registry<\/a> and <a href=\"https:\/\/github.com\/lidofinance\/community-staking-module\" target=\"_blank\" rel=\"noopener\">Community Staking Module v2<\/a>. More details about the fuzzing process can be found in the full audit report linked at the end of this article.<\/p>\n<p>In parallel, we performed an in-depth manual review of the code, especially focusing on the triggerable withdrawal functionality, compatibility with <a href=\"https:\/\/eips.ethereum.org\/EIPS\/eip-7002\" target=\"_blank\" rel=\"noopener\">EIP-7002<\/a>, and new code changes since the last audit (commit <code class=\"codehl\">1ffbb7e<\/code>). During the review, we focused on the following:<\/p>\n<ul>\n<li>permissionless mechanism of triggering validator exits;<\/li>\n<li>compatibility with EIP-7002;<\/li>\n<li>exploring new attack vectors due to triggerable withdrawals functionality;<\/li>\n<li>permissionless mechanism for reporting of exit delayed validators;<\/li>\n<li>checking that all state variables are properly updated and do not break any invariants;<\/li>\n<li>ensuring access controls are not too relaxed or too strict; and<\/li>\n<li>looking for common issues such as data validation.<\/li>\n<\/ul>\n<p>Static analysis tools were used to review the code as well and yielded findings I4 and I5.<\/p>\n<h2><span style=\"font-weight: 400;\">SCOPE<\/span><\/h2>\n<p>The first audit was performed on commit <code class=\"codehl\">628c873<\/code> in the <a href=\"https:\/\/github.com\/lidofinance\/core\" target=\"_blank\" rel=\"noopener\">core<\/a> repository and the scope was the following:<\/p>\n<ul>\n<li><code class=\"codehl\">contracts\/0.4.24\/nos\/NodeOperatorRegistry.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.9\/LidoLocator.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.9\/StakingRouter.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.9\/TriggerableWithdrawalsGateway.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.9\/WithdrawalVault.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.9\/WithdrawalVaultEIP7002.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.9\/oracle\/AccountingOracle.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.9\/oracle\/ValidatorsExitBus.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.9\/oracle\/ValidatorsExitBusOracle.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.9\/lib\/ExitLimitUtils.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.25\/lib\/BeaconTypes.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.25\/lib\/GIndex.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.25\/lib\/SSZ.sol<\/code><\/li>\n<li><code class=\"codehl\">contracts\/0.8.25\/ValidatorExitDelayVerifier.sol<\/code><\/li>\n<\/ul>\n<p>The initial review commit <code class=\"codehl\">8beee97<\/code> was changed 4 days after the beginning of the audit to the commit <code class=\"codehl\">628c873<\/code>.<\/p>\n<h2><span style=\"font-weight: 400;\">FINDINGS<\/span><\/h2>\n<p>The classification of a security finding is determined by two sub-ratings: Impact and Likelihood. This two-dimensional rating makes the severity of issues more noise-free, without losing any information. The likelihood factor usually decreases severity of medium issues that would be just acknowledged by the team to infos and warning.<\/p>\n<p>Our review resulted in <strong>11 findings<\/strong> ranging from Info to Low severity. The most severe findings, L1 and L2, relate to the limited responsiveness of the system upon changing the exit limits configuration parameters and inconsistency in the total number of processed exit requests, respectively. The overall code quality is high, with comprehensive documentation and good architecture.<\/p>\n<h3>Critical severity<\/h3>\n<p>No critical severity issues were found.<\/p>\n<h3>High severity<\/h3>\n<p>No high severity issues were found.<\/p>\n<h3>Medium severity<\/h3>\n<p>No medium severity issues were found.<\/p>\n<h3>Low severity<\/h3>\n<p>L1: Inconsistent update of exit limits on config change<\/p>\n<p>L2: Inconsistent calculation of total requests processed<\/p>\n<h3>Warning severity<\/h3>\n<p>W1: Unimplemented function called<\/p>\n<p>W2: Missing interface inheritance<\/p>\n<p>W3: Outdated <code class=\"codehl\">IConsensusContract<\/code> interface<\/p>\n<p>W4: <code class=\"codehl\">_setExitDeadlineThreshold<\/code> underflow<\/p>\n<h3>Informational severity<\/h3>\n<p>I1: Code optimizations<\/p>\n<p>I2: Lack of event emission<\/p>\n<p>I3: Lack of context in deprecated function NatSpec<\/p>\n<p>I4: Unused errors<\/p>\n<p>I5: Unused using-for directive<\/p>\n<h2><span style=\"font-weight: 400;\">TRUST MODEL<\/span><\/h2>\n<p>Lido allows permissionless triggering of validator exits if the validator is included in a report submitted via Easy Track or Oracle. The protocol relies on two trusted components for submitting withdrawal reports:<\/p>\n<p>The flow for triggering validator exit via Easy Track is as follows:<\/p>\n<ol>\n<li>The hash of the report is submitted by an address with the <code class=\"codehl\">SUBMIT_REPORT_HASH_ROLE<\/code> role, which is assigned to Easy Track;<\/li>\n<li>Anyone can submit report data with the same hash provided in the first step; and<\/li>\n<li>Anyone can trigger the exit of a validator included in the report.<\/li>\n<\/ol>\n<p>The flow for triggering validator exit via Oracle is as follows:<\/p>\n<ol>\n<li>The hash of the report is submitted by the consensus contract;<\/li>\n<li>The report data is submitted by an address with the <code class=\"codehl\">SUBMIT_DATA_ROLE<\/code> role or by a consensus member; and<\/li>\n<li>Anyone can trigger the exit of a validator included in the report.<\/li>\n<\/ol>\n<p>Easy Track is an on-chain component that conducts lightweight voting; a proposal passes if the minimum objections threshold is not reached.<\/p>\n<p>The Trigger Exits Bot is an off-chain component that ensures withdrawal requests are not unnecessarily stalled so that users experience smooth exits.<\/p>\n<p>The Validator Late Prover Bot is an automated tool to detect and report late validators who have failed to exit within the required timeframe after an exit request.<\/p>\n<p>An address with the <code class=\"codehl\">ADD_FULL_WITHDRAWAL_REQUEST_ROLE<\/code> role can submit withdrawal requests via the Triggerable Withdrawal Gateway.<\/p>\n<p>Staking Router functions require specific roles to be assigned to the caller\u2019s address.<\/p>\n<h2><span style=\"font-weight: 400;\">CONCLUSION<\/span><\/h2>\n<p><b>Ackee Blockchain Security recommended Lido Finance to:<\/b><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\">ensure contract upgrade and initialization are atomic to prevent frontrunning attacks possibly leading to loss of control over the contract;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\">always inherit from interfaces in the contracts that implement them; and<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\">address all identified issues.<\/li>\n<\/ul>\n<p><b>Ackee Blockchain Security\u2019s full Lido Finance Triggerable Withdrawals audit report can be found <a href=\"https:\/\/github.com\/lidofinance\/audits\/blob\/main\/Ackee%20Blockchain%20Lido%20Triggerable%20Withdrawals%20Audit%20Report%2009-25.pdf\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/b><\/p>\n<p><span style=\"font-weight: 400;\">We were delighted to audit Lido Finance and look forward to working with them again.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lido is a decentralized liquid staking protocol for Ethereum. Triggerable withdrawals is a new feature based on the EIP-7002 standard that allows for the ejection of validators previously deposited through the Lido protocol. The primary purpose of triggerable withdrawals is to allow the Lido DAO to withdraw funds locked in a validator when the node operator refuses to submit a withdrawal request.&hellip;<\/p>\n","protected":false},"author":30,"featured_media":1197,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20,10,103],"tags":[89,24,28],"class_list":["post-1195","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-audits","category-ethereum","category-wake","tag-audit-summary","tag-ethereum","tag-smart-contract"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/10\/lido-cover-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/10\/lido-cover-600x600.png","author_info":{"display_name":"Tom\u00e1\u0161 Kova\u0159\u00edk","author_link":"https:\/\/ackee.xyz\/blog\/author\/tomas-kovarik\/"},"_links":{"self":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/1195","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/users\/30"}],"replies":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/comments?post=1195"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/1195\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/1197"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=1195"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=1195"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=1195"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}