{"id":1087,"date":"2025-08-21T15:18:28","date_gmt":"2025-08-21T13:18:28","guid":{"rendered":"https:\/\/ackee.xyz\/blog\/?p=1087"},"modified":"2025-09-08T15:53:46","modified_gmt":"2025-09-08T13:53:46","slug":"complete-reentrancy-hands-on-guide","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/complete-reentrancy-hands-on-guide\/","title":{"rendered":"Complete Reentrancy Hands-on Guide"},"content":{"rendered":"<p>This guide provides a comprehensive analysis\u00a0of reentrancy vulnerabilities with\u00a0practical, executable examples for each attack type. Learn\u00a0how different reentrancy patterns work\u00a0and how to identify them in real\u00a0protocols.<\/p>\n<h2><strong>What\u00a0is reentrancy?<\/strong><\/h2>\n<p>Reentrancy occurs\u00a0when an external contract call\u00a0recursively calls back into the calling function\u00a0before it completes execution. During\u00a0external calls, control passes\u00a0to the recipient contract, which\u00a0can execute arbitrary code. If state updates happen <strong>after<\/strong>\u00a0the external call, attackers can re-enter the function\u00a0and drain funds.<\/p>\n<p>Reentrancy hacks\u00a0are still happening today. For\u00a0a comprehensive list of historical reentrancy exploits, see\u00a0<a href=\"https:\/\/github.com\/pcaversaccio\/reentrancy-attacks\">pcaversaccio&#8217;s reentrancy-attacks repository<\/a>.<\/p>\n<p>Any\u00a0contract that makes external calls is potentially\u00a0vulnerable, especially those related to withdrawal mechanisms, DeFi protocols, and cross-chain bridges.<\/p>\n<h2>How to prevent reentrancies?<\/h2>\n<p>Follow\u00a0the Checks-Effects-Interactions (CEI) pattern: perform checks, update state, and only then make external calls. This\u00a0ordering prevents exploitation of inconsistent states.<\/p>\n<p>ReentrancyGuard prevents single-contract reentrancy but not cross-contract attacks. Use pull payment patterns and minimise external calls for better security.<\/p>\n<p><a href=\"https:\/\/getwake.io\">Wake<\/a>&#8216;s Python-based framework\u00a0includes reentrancy detection through static analysis and testing patterns, identifying vulnerabilities before deployment.<\/p>\n<h2><strong>Identifying reentrancy vulnerabilities<\/strong><\/h2>\n<p>Key attack vectors include:<\/p>\n<ul>\n<li>Functions making external calls before state updates<\/li>\n<li>Token\u00a0standards with hooks (ERC-777, ERC-1155)<\/li>\n<li>Flash loan implementations<\/li>\n<li>Cross-chain messaging systems<\/li>\n<\/ul>\n<p><strong>Every external call is\u00a0a potential vulnerability point.<\/strong><\/p>\n<h2><strong>Types of reentrancy attacks<\/strong><\/h2>\n<p>Reentrancy ranges from simple recursive calls to complex multi-contract exploits. Each type requires different defensive strategies. Developers must consider all attack possibilities during development. Let&#8217;s take a closer look at the mechanics of these critical vulnerabilities.<\/p>\n<h3><strong>Single-function reentrancy<\/strong><\/h3>\n<p>In a <a href=\"https:\/\/ackee.xyz\/blog\/single-function-reentrancy-attack\/\">single-function reentrancy<\/a>, attackers recursively call the same function during external calls. It is most common in withdrawal functions that send ETH before updating balances.<\/p>\n<p><strong>Example vulnerability:<\/strong><\/p>\n<pre><code class=\"language-solidity\">function\u00a0withdraw()\u00a0public\u00a0{\n\t\tuint256\u00a0amount\u00a0=\u00a0balances[msg.sender];\n\t\t(bool\u00a0success,\u00a0)\u00a0=\u00a0msg.sender.call{value:\u00a0amount}(&quot;&quot;);\n\t\trequire(success,\u00a0&quot;Failed\u00a0to\u00a0send\u00a0Ether&quot;);\n\t\tbalances[msg.sender]\u00a0=\u00a00;\u00a0\/\/\u00a0State\u00a0updated\u00a0after\u00a0external\u00a0call\n}<\/code><\/pre>\n<p><strong>Attack steps:<\/strong><\/p>\n<ol>\n<li>Attacker deposits\u00a0funds and calls\u00a0<code class=\"codehl\">withdraw()<\/code><\/li>\n<li>During the\u00a0external call, attacker&#8217;s contract re-enters\u00a0<code class=\"codehl\">withdraw()<\/code><\/li>\n<li>Balance hasn&#8217;t been reset\u00a0yet, so withdrawal succeeds again<\/li>\n<li>Process\u00a0repeats until contract is drained<\/li>\n<\/ol>\n<p><strong>Prevention:<\/strong>\u00a0Update state before external calls following the CEI pattern.<\/p>\n<h3><strong>Cross-function reentrancy<\/strong><\/h3>\n<p><a href=\"https:\/\/ackee.xyz\/blog\/cross-function-reentrancy-attack\/\">Cross-function reentrancy<\/a> exploits multiple functions within one contract. It gets dangerous when developers protect individual functions but miss their interactions.<\/p>\n<p><strong>Example vulnerability:<\/strong><\/p>\n<pre><code class=\"language-solidity\">contract\u00a0Vault\u00a0is\u00a0ReentrancyGuard\u00a0{\n\t\tfunction\u00a0transfer(address\u00a0to,\u00a0uint256\u00a0amount)\u00a0public\u00a0{\n\t\t\t\t\/\/\u00a0No\u00a0reentrancy\u00a0protection\u00a0here\n\t\t\t\tif\u00a0(balances[msg.sender]\u00a0&gt;=\u00a0amount)\u00a0{\n\t\t\t\t\t\tbalances[to]\u00a0+=\u00a0amount;\n\t\t\t\t\t\tbalances[msg.sender]\u00a0-=\u00a0amount;\n\t\t\t\t}\n\t\t}\n\t\tfunction\u00a0withdraw()\u00a0public\u00a0nonReentrant\u00a0{\n\t\t\t\tuint256\u00a0amount\u00a0=\u00a0balances[msg.sender];\n\t\t\t\t(bool\u00a0success,\u00a0)\u00a0=\u00a0msg.sender.call{value:\u00a0amount}(&quot;&quot;);\n\t\t\t\trequire(success,\u00a0&quot;Failed\u00a0to\u00a0send\u00a0Ether&quot;);\n\t\t\t\tbalances[msg.sender]\u00a0=\u00a00;\n\t\t}\n}<\/code><\/pre>\n<p><strong>Attack vector:<\/strong>\u00a0Attacker re-enters through\u00a0unprotected\u00a0<code class=\"codehl\">transfer()<\/code>\u00a0during\u00a0<code class=\"codehl\">withdraw()<\/code>\u00a0external call, manipulating balances before the withdrawal completes.<\/p>\n<p><strong>Prevention:<\/strong>\u00a0Apply\u00a0reentrancy guards to all state-modifying functions or use CEI pattern consistently.<\/p>\n<h3><strong>Cross-chain reentrancy<\/strong><\/h3>\n<p>As the name implies, <a href=\"https:\/\/ackee.xyz\/blog\/cross-chain-reentrancy-attack\/\">cross-chain reentrancy<\/a> manipulates cross-chain messaging to mint duplicate tokens across chains. This makes it critical for bridge implementations.<\/p>\n<p><strong>Vulnerability pattern:<\/strong>\u00a0Cross-chain contracts\u00a0often increment counters or update state after\u00a0external calls like\u00a0<code class=\"codehl\">_safeMint()<\/code>. If an attacker re-enters during\u00a0the external call, they can trigger the same cross-chain event multiple times before state\u00a0updates.<\/p>\n<p><strong>Real impact:<\/strong>\u00a0Same\u00a0<code class=\"codehl\">tokenId<\/code>\u00a0minted on multiple chains, breaking\u00a0bridge accounting and creating phantom tokens.<\/p>\n<p><strong>Prevention:<\/strong><\/p>\n<ul>\n<li>Update cross-chain state variables before external calls<\/li>\n<li>Implement post-call verification of\u00a0critical variables<\/li>\n<li>Use reentrancy guards\u00a0on cross-chain functions<\/li>\n<\/ul>\n<h3><strong>Cross-contract reentrancy<\/strong><\/h3>\n<p><a href=\"https:\/\/ackee.xyz\/blog\/cross-contract-reentrancy-attack\/\">Cross-contract reentrancy<\/a> spans\u00a0multiple contracts, bypassing <code class=\"codehl\">ReentrancyGuard<\/code>. This means it requires comprehensive interaction analysis.<\/p>\n<p><strong>Attack\u00a0pattern:<\/strong>\u00a0Contract A protected with\u00a0ReentrancyGuard calls Contract B. During Contract A&#8217;s external call, attacker re-enters through Contract B&#8217;s unprotected functions, manipulating shared state.<\/p>\n<p><strong>Example\u00a0scenario:<\/strong>\u00a0Vault contract with ReentrancyGuard uses\u00a0separate Token contract. Attacker re-enters through Token\u00a0contract&#8217;s transfer function during Vault&#8217;s withdrawal process.<\/p>\n<p><strong>Prevention:<\/strong>\u00a0Implement consistent reentrancy protection across all interacting contracts and follow CEI pattern in\u00a0contract interactions.<\/p>\n<h3><strong>Read-only reentrancy<\/strong><\/h3>\n<p><a href=\"https:\/\/ackee.xyz\/blog\/read-only-reentrancy-attack\/\">Read-only reentrancy<\/a> exploits view functions during\u00a0state transitions. This makes it critical in DeFi protocols relying on price oracles.<\/p>\n<p><strong>Vulnerability mechanism:<\/strong>\u00a0View functions appear safe but can\u00a0return inconsistent data during state transitions. Attackers exploit\u00a0this window to get incorrect price calculations.<\/p>\n<p><strong>Example\u00a0scenario:<\/strong><\/p>\n<pre><code class=\"language-solidity\">function\u00a0getCurrentPrice()\u00a0public\u00a0view\u00a0returns\u00a0(uint256)\u00a0{\n\t\tif\u00a0(totalTokens\u00a0==\u00a00)\u00a0return\u00a010e18;\n\t\treturn\u00a0(totalTokens\u00a0*\u00a010e18)\u00a0\/\u00a0totalStake;\n}<\/code><\/pre>\n<p>During\u00a0external calls,\u00a0totalStake\u00a0might\u00a0be updated while\u00a0totalTokens\u00a0remains unchanged, creating price manipulation\u00a0opportunities.<\/p>\n<p><strong>Prevention:<\/strong>\u00a0Avoid view functions dependent on mutable state during external calls. Implement state consistency checks.<\/p>\n<h2><strong>Protocol-specific vulnerabilities<\/strong><\/h2>\n<h3><strong>Flash loan reentrancy<\/strong><\/h3>\n<p>In a <a href=\"https:\/\/ackee.xyz\/blog\/flash-loan-reentrancy-attack\/\">flash loan reentrancy<\/a>, attackers manipulate token balances during loan\u00a0execution by exploiting improper balance verification. Creates &#8220;side entrance&#8221; attacks where attackers use\u00a0flash loans to temporarily inflate balances, bypass\u00a0checks, then extract funds through different withdrawal mechanisms.<\/p>\n<p><strong>Common pattern:<\/strong>\u00a0Flash loan increases\u00a0user&#8217;s balance, triggering withdrawal logic\u00a0that doesn&#8217;t account for the temporary balance inflation.<\/p>\n<h3><strong>ERC-721 reentrancy<\/strong><\/h3>\n<p>In an\u00a0<a href=\"https:\/\/ackee.xyz\/blog\/reentrancy-attack-in-erc-721\/\">ERC-721 reentrancy<\/a>, the <code class=\"codehl\">onERC721Received<\/code>\u00a0callback enables attacks during NFT transfers. Critical for marketplaces and staking contracts\u00a0where NFT transfers trigger state changes or\u00a0payments.<\/p>\n<p><strong>Attack vector:<\/strong>\u00a0Malicious contracts can re-enter during\u00a0<code class=\"codehl\">_safeMint<\/code>\u00a0or\u00a0safeTransferFrom\u00a0calls, manipulating contract state before NFT transfer completes.<\/p>\n<h3><strong>ERC-777 reentrancy<\/strong><\/h3>\n<p>In an <a href=\"https:\/\/ackee.xyz\/blog\/reentrancy-attack-in-erc-777\/\">ERC-777 reentrancy<\/a>, transfer\u00a0hooks break CEI patterns, enabling price manipulation. Advanced token features increase vulnerability surface\u00a0area.<\/p>\n<p><strong>Mechanism:<\/strong>\u00a0tokensReceived\u00a0hooks execute\u00a0during transfers, allowing attackers to re-enter sending\u00a0contracts and manipulate state mid-transfer.<\/p>\n<h3><strong>ERC-1155 reentrancy<\/strong><\/h3>\n<p>In an <a href=\"https:\/\/ackee.xyz\/blog\/reentrancy-attack-in-erc-1155\/\">ERC-1155 reentrancy<\/a>, Multi-token callbacks (<code class=\"codehl\">onERC1155Received,\u00a0onERC1155BatchReceived<\/code>) create attack vectors in blockchain protocols.<\/p>\n<p><strong>Complexity factor:<\/strong>\u00a0Batch\u00a0operations create multiple reentrancy opportunities within\u00a0single transactions, requiring careful state management.<\/p>\n<h2><strong>Conclusion<\/strong><\/h2>\n<p>Every external call is\u00a0a potential reentrancy vulnerability. Follow\u00a0CEI patterns, understand ReentrancyGuard limitations, and analyse\u00a0all contract interactions.<\/p>\n<p>As protocols become more complex with\u00a0cross-chain bridges and advanced token standards, new\u00a0attack patterns emerge. Security-first development is\u00a0essential.<\/p>\n<p>Modern DeFi protocols require comprehensive\u00a0reentrancy analysis beyond a single-contract scope. Consider cross-contract interactions, token\u00a0hooks, and read-only function dependencies\u00a0when designing secure systems.<\/p>\n<p>We hope that this overview will help you write safer code. Every reentrancy attack mentioned above has a deep-dive article linked in its respective section, so read on to learn more.<\/p>\n<h2><!-- notionvc: 1786d671-2e19-4495-ae86-7b8bcd2141e9 --><\/h2>\n<div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>This guide provides a comprehensive analysis\u00a0of reentrancy vulnerabilities with\u00a0practical, executable examples for each attack type. Learn\u00a0how different reentrancy patterns work\u00a0and how to identify them in real\u00a0protocols. What\u00a0is reentrancy? Reentrancy occurs\u00a0when an external contract call\u00a0recursively calls back into the calling function\u00a0before it completes execution. During\u00a0external calls, control passes\u00a0to the recipient contract, which\u00a0can execute arbitrary code. If state updates happen after\u00a0the external call, attackers&hellip;<\/p>\n","protected":false},"author":24,"featured_media":1061,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[61,10,85,84,80,63,103],"tags":[96,14,88,28,102],"class_list":["post-1087","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-education","category-ethereum","category-exploits","category-hacks","category-solidity","category-tutorial","category-wake","tag-educational","tag-exploit","tag-how-to","tag-smart-contract","tag-tutorial"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/06\/kiloex-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/06\/kiloex-600x600.png","author_info":{"display_name":"Naoki Yoshida","author_link":"https:\/\/ackee.xyz\/blog\/author\/naoki-yoshida\/"},"_links":{"self":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/1087","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\/24"}],"replies":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/comments?post=1087"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/1087\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/1061"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=1087"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=1087"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=1087"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}