{"id":988,"date":"2025-02-12T19:42:03","date_gmt":"2025-02-12T17:42:03","guid":{"rendered":"https:\/\/ackee.xyz\/blog\/?p=988"},"modified":"2025-02-26T18:00:50","modified_gmt":"2025-02-26T16:00:50","slug":"leech-protocol-audit-summary","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/leech-protocol-audit-summary\/","title":{"rendered":"Leech Protocol Audit Summary"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">Leech is a cross-chain protocol enabling multichain yield farming via Stargate bridge, aggregating yielding strategies in a user interface for their management.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">METHODOLOGY<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">We began our review using static analysis tools, including <\/span><a href=\"https:\/\/getwake.io\/\"><span style=\"font-weight: 400;\">Wake<\/span><\/a><span style=\"font-weight: 400;\">. We then took a deep dive into the logic of the contracts. After writing simple unit tests, we prepared a <\/span><a href=\"https:\/\/ackee.xyz\/blog\/introducing-manually-guided-fuzzing-a-new-approach-in-smart-contract-testing\/\"><span style=\"font-weight: 400;\">manually-guided differential forking fuzz test<\/span><\/a><span style=\"font-weight: 400;\"> to verify protocol implementation and integration with external dependencies, including Velodrome V2 and Velodrome V3.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">SCOPE<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">The audit was performed on strategies for Velodrome V2 and Velodrome V3, and the commit <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">ba2a75<\/code><\/span><span style=\"font-weight: 400;\">. The scope was the following:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">contracts\/core\/LeechRouter.sol<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">contracts\/core\/LeechSwapper.sol contracts\/core\/BanList.sol contracts\/core\/rewarder\/Rewarder.sol<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">contracts\/strategies\/BaseStrategy.sol<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">contracts\/strategies\/farming\/Velodrome\/StrategyVelodromeV2StableFarm.sol<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">contracts\/strategies\/farming\/Velodrome\/StrategyVelodromeV2StableCHID AIFarm.sol<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">contracts\/strategies\/farming\/VelodromeV3\/StrategyVelodromeV3StableFarm.sol<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">contracts\/strategies\/farming\/VelodromeV3\/StrategyVelodromeV3_USDC_LUSD.sol\u00a0<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">contracts\/strategies\/farming\/VelodromeV3\/StrategyVelodromeV3_USDC_SDAI.sol<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">contracts\/strategies\/farming\/VelodromeV3\/StrategyVelodromeV3_USDC_SUSD.sol<\/span><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">The second revision was conducted on commit <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">caafd3<\/code><\/span><span style=\"font-weight: 400;\">, which included the fix of C1. The third revision was then conducted on commit <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">4245d0<\/code><\/span><span style=\"font-weight: 400;\">, reviewing the fix of H1.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">FINDINGS<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">The classification of a security finding is determined by two ratings: <\/span><b>impact<\/b><span style=\"font-weight: 400;\"> and <\/span><b>likelihood<\/b><span style=\"font-weight: 400;\">. This two-dimensional classification helps clarify the severity of individual issues. Issues which would be rated as <\/span><i><span style=\"font-weight: 400;\">medium<\/span><\/i><span style=\"font-weight: 400;\"> severity, but which would be likely discovered only by the team, are typically decreased by the likelihood factor to the <\/span><i><span style=\"font-weight: 400;\">warning<\/span><\/i><span style=\"font-weight: 400;\"> or <\/span><i><span style=\"font-weight: 400;\">informational<\/span><\/i><span style=\"font-weight: 400;\"> severity ratings.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The audit resulted in <\/span><b>32 total findings <\/b><span style=\"font-weight: 400;\">ranging from informational to critical severity<\/span><b>. <\/b><span style=\"font-weight: 400;\">12 were identified using <\/span><a href=\"https:\/\/getwake.io\"><span style=\"font-weight: 400;\">Wake<\/span><\/a><span style=\"font-weight: 400;\">&#8216;s static analysis. The detailed outputs from Wake (including code snippets) are available in the <\/span><a href=\"https:\/\/github.com\/Ackee-Blockchain\/public-audit-reports\/blob\/master\/2025\/ackee-blockchain-leech-protocol-leech-protocol-report.pdf\"><span style=\"font-weight: 400;\">full audit summary<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">During manual review, we checked if:\u00a0<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">External calls to untrusted contracts cannot be abused for reentrancy;\u00a0<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Cross-chain interaction is correctly implemented;\u00a0<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">The arithmetic of internal accounting is correct;\u00a0<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Access controls are not too relaxed or too strict;\u00a0<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Token arithmetic inside the protocol match the documentation and expectations;\u00a0<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">The integration with external dependencies is correctly implemented; and\u00a0<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">There are any common issues such as data validation.\u00a0\u00a0<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">The most severe finding C1 posed a risk of loss of all funds transferred cross-chain to the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">LeechRouter<\/code><\/span><span style=\"font-weight: 400;\"> due to the non-atomicity of cross-chain transactions executed by the protocol. <\/span><b>This critical vulnerability was discovered in already-deployed Leech protocol contracts<\/b><span style=\"font-weight: 400;\"> on several chains, including Optimism and Binance Smart Chain.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Ackee Blockchain Security initiated an immediate responsible disclosure to Leech as soon as the findings were discovered. Thanks to prompt engagement, all assets were protected by pausing cross-chain transactions.<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Critical severity<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">C1: Lack of atomicity in cross-chain transactions<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">High severity<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">H1: Donation attack<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Medium severity<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">M1: <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">data.swapperAddress<\/code><\/span><span style=\"font-weight: 400;\"> is not checked in the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">withdraw<\/code><\/span><span style=\"font-weight: 400;\"> function<\/span><\/p>\n<p><span style=\"font-weight: 400;\">M2: Initialization function vulnerable to frontrunning<\/span><\/p>\n<p><span style=\"font-weight: 400;\">M3: The <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">strategy.poolShare<\/code><\/span><span style=\"font-weight: 400;\"> attribute is not checked properly<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Low severity<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">L1: No error reported if no bridge configured<\/span><\/p>\n<p><span style=\"font-weight: 400;\">L2: Pool configuration data can be overwritten<\/span><\/p>\n<p><span style=\"font-weight: 400;\">L3: Oracle price feed data validation missing<\/span><\/p>\n<p><span style=\"font-weight: 400;\">L4: External interaction with Chainlink is not handled appropriately<\/span><\/p>\n<p><span style=\"font-weight: 400;\">L5: Two-step ownership is not used<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Warning severity<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">W1: Using <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">transfer<\/code><\/span><span style=\"font-weight: 400;\"> instead of <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">call<\/code><\/span><\/p>\n<p><span style=\"font-weight: 400;\">W2: Direct token balance checks using <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">balanceof(address(this))<\/code><\/span><span style=\"font-weight: 400;\"> present a security risk<\/span><\/p>\n<p><span style=\"font-weight: 400;\">W3: Getter of <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">pools<\/code><\/span><span style=\"font-weight: 400;\"> does not return all members of a complex structure<\/span><\/p>\n<p><span style=\"font-weight: 400;\">W4: Unnecessary token swaps in withdrawal process<\/span><\/p>\n<p><span style=\"font-weight: 400;\">W5: Epoch time range overlap in reward distribution<\/span><\/p>\n<p><span style=\"font-weight: 400;\">W6: Account abstraction users cannot receive unused funds back<\/span><\/p>\n<p><span style=\"font-weight: 400;\">W7: Missing storage gaps<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Informational severity<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">I1: <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">console.log<\/code><\/span><span style=\"font-weight: 400;\"> statements present in production code<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I2: Unused custom error declarations<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I3: Unused event declarations<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I4: Autocompound function lacks access control<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I5: Unused contract functions<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I6: Unused imports<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I7: Unused modifiers<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I8: Unused <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">using for<\/code><\/span><\/p>\n<p><span style=\"font-weight: 400;\">I9: Inconsistent <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">msg.sender<\/code><\/span><span style=\"font-weight: 400;\"> role validation in pause functions<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I10: The <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">initializePosition<\/code><\/span><span style=\"font-weight: 400;\"> function in Velodrome V3 strategies should be external<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I11: Unused function parameters<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I12: Inconsistent parameter naming in <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">setRoutes<\/code><\/span><span style=\"font-weight: 400;\"> functions across Velodrome strategies<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I13: Unused multichain integration code present in codebase<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I14: Unused interface and library<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I15: Incorrect event name in NatSpec documentation<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">TRUST MODEL<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Users had to trust:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">The protocol <\/span><b>finalizer<\/b><span style=\"font-weight: 400;\">, an off-chain component responsible for finalizing cross-chain transactions and having withdrawal privileges for all protocol funds.<\/span><\/li>\n<\/ul>\n<h2><span style=\"font-weight: 400;\">CONCLUSION<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">The most severe finding C1 posed a risk of loss of all funds transferred cross-chain to the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">LeechRouter<\/code><\/span><span style=\"font-weight: 400;\"> due to the non-atomicity of cross-chain transactions executed by the protocol. <\/span><b>This critical vulnerability was discovered in already-deployed Leech protocol contracts<\/b><span style=\"font-weight: 400;\"> on several chains, including Optimism and Binance Smart Chain.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Ackee Blockchain Security initiated an immediate responsible disclosure to Leech as soon as the findings were discovered. Thanks to prompt engagement, all assets were protected by pausing cross-chain transactions. The C1 vulnerablility was fixed and the finalizer removed.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">We would also like to thank <\/span><a href=\"https:\/\/gov.optimism.io\/t\/cycle-29-final-roundnup\/9211\"><span style=\"font-weight: 400;\">Optimism\u2019s <\/span><span style=\"font-weight: 400;\">Subsidized Audit Grants V2<\/span><span style=\"font-weight: 400;\"> program<\/span><\/a><span style=\"font-weight: 400;\"> for funding Leech&#8217;s audit. Without the support from Optimism, these vulnerabilities could have gone unnoticed.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Ackee Blockchain Security recommends Leech to:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Reconsider the design of cross-chain transactions in the protocol;\u00a0<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Ensure all Chainlink feed registry contracts maintained by Leech provide up-to-date price feeds and comply with expected behavior; and<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Address all other reported issues.<\/span><\/li>\n<\/ul>\n<p><b>Ackee Blockchain Security\u2019s full Leech audit report can be found <\/b><a href=\"https:\/\/github.com\/Ackee-Blockchain\/public-audit-reports\/blob\/master\/2025\/ackee-blockchain-leech-protocol-leech-protocol-report.pdf\"><b>here<\/b><\/a><b>.<\/b><\/p>\n<p><span style=\"font-weight: 400;\">We were delighted to audit Leech and look forward to working with them again.<\/span><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Leech is a cross-chain protocol enabling multichain yield farming via Stargate bridge, aggregating yielding strategies in a user interface for their management. METHODOLOGY We began our review using static analysis tools, including Wake. We then took a deep dive into the logic of the contracts. After writing simple unit tests, we prepared a manually-guided differential forking fuzz test to verify protocol implementation&hellip;<\/p>\n","protected":false},"author":30,"featured_media":989,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20,10,103],"tags":[89,24,104],"class_list":["post-988","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-audits","category-ethereum","category-wake","tag-audit-summary","tag-ethereum","tag-wake"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/02\/leech-protocol-blog-head-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/02\/leech-protocol-blog-head-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\/988","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=988"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/988\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/989"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=988"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=988"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=988"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}