{"id":802,"date":"2025-03-17T13:14:35","date_gmt":"2025-03-17T11:14:35","guid":{"rendered":"https:\/\/ackee.xyz\/blog\/?p=802"},"modified":"2025-03-21T10:25:19","modified_gmt":"2025-03-21T08:25:19","slug":"cross-chain-reentrancy-attack","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/cross-chain-reentrancy-attack\/","title":{"rendered":"Cross-chain Reentrancy Attack"},"content":{"rendered":"<p dir=\"auto\" data-line=\"2\">A cross-chain reentrancy attack is an exploit that targets smart contract function calls across different chains, and can lead to loss of funds in the smart contract. Learn more about this vulnerability with examples to ensure your code doesn&#8217;t leave open doors to attackers.<\/p>\n<h2 dir=\"auto\" data-line=\"2\">The vulnerability<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"2\">Events emitted at inappropriate locations in code can create cross-chain reentrancy vulnerabilities. Such an event could be used to trigger a call on a different chain while still incomplete on the original one. You can find example code to run in your environment <a href=\"https:\/\/github.com\/Ackee-Blockchain\/reentrancy-examples\/tree\/master\/contracts\/cross-chain-reentrancy\">here<\/a>.<\/p>\n<h2 id=\"example-contract\" class=\"code-line\" dir=\"auto\" data-line=\"4\">Example contract<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"6\">This is an example of a vulnerable contract: it can be deployed on multiple chains. It allows minting from only one designated chain while enabling transfer tokens between chains. This means only one token with the same <code class=\"codehl\">tokenId<\/code> on multiple chains should exist.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"10\">By calling the\u00a0<code class=\"codehl\">crossChainTransfer<\/code> function, the user can transfer tokens. This burns the token on the source chain. The action emits a message relayed by a validator off-chain. These validators then call the function on the destination chain, minting a token with a specified <code class=\"codehl\">tokenId<\/code>.<\/p>\n<p><script src=\"https:\/\/gist.github.com\/MeditationDuck\/05130722bf00237cdcfa5a8533c267b2.js\"><\/script><\/p>\n<h2 id=\"attack-example\" class=\"code-line\" dir=\"auto\" data-line=\"120\">Attack example<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"122\">The vulnerability is in the minting process. There is an external call when minting via <code class=\"codehl\">_safeMint<\/code> to confirm the possibility of a lockout token. Furthermore, <code class=\"codehl\">tokenIds++;<\/code> follows after the <code class=\"codehl\">_safeMint<\/code>\u00a0function call.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"125\">An attacker can exploit this by doing the following:<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"127\">While in the external call, i.e. in the <code class=\"codehl\">onERC721Received<\/code> function, they can call the <code class=\"codehl\">crossChainTransfer<\/code> function and call <code class=\"codehl\">mint<\/code>\u00a0again.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"131\">This creates a situation where <code class=\"codehl\">tokenIds++;<\/code> executes twice, resulting in identical <code class=\"codehl\">tokenId<\/code> tokens existing on multiple chains.<\/p>\n<h3 id=\"attacker-contract\" class=\"code-line\" dir=\"auto\" data-line=\"135\">Attacker contract<\/h3>\n<p><script src=\"https:\/\/gist.github.com\/MeditationDuck\/c7f97d6113768d73b42472263634c25c.js\"><\/script><\/p>\n<h3 id=\"wake-code\" class=\"code-line\" dir=\"auto\" data-line=\"193\">Wake code<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"195\">In our testing environment, we have two different chains: chain1 and chain2. In the <code class=\"codehl\">test_expected_usage<\/code> function, we are sending tokens from chain1 to chain2 through a relay. The relay captures events emitted on chain1 and forwards those events with messages to the chain2. This call is only allowed by the validator, so we are sending it via the validator of each chain using <code class=\"codehl\">from_=validator_chain1<\/code>\u00a0and so on.<\/p>\n<p><script src=\"https:\/\/gist.github.com\/MeditationDuck\/5317a8ca6c33bf8f878bbafd27485ef4.js\"><\/script><\/p>\n<h3 id=\"wake-output\" class=\"code-line\" dir=\"auto\" data-line=\"281\">Wake output<\/h3>\n<p>We could create the same <code class=\"codehl\">tokenId<\/code> token on two chains.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"283\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-803\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2024\/06\/Screenshot-from-2024-06-21-17-34-25.png\" alt=\"\" width=\"710\" height=\"375\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2024\/06\/Screenshot-from-2024-06-21-17-34-25.png 710w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2024\/06\/Screenshot-from-2024-06-21-17-34-25-300x158.png 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2024\/06\/Screenshot-from-2024-06-21-17-34-25-370x195.png 370w\" sizes=\"auto, (max-width: 710px) 100vw, 710px\" \/><\/p>\n<h2 id=\"prevension\" class=\"code-line\" dir=\"auto\" data-line=\"286\">Prevention<\/h2>\n<h3 id=\"checks-effects-interactions\" class=\"code-line\" dir=\"auto\" data-line=\"288\">Checks-effects-interactions<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"290\">This prevention method ensures state changes are completed before external calls.<\/p>\n<p><script src=\"https:\/\/gist.github.com\/MeditationDuck\/904c7ad9f6d212ebf5b9922b453d88af.js\"><\/script><\/p>\n<h3 id=\"reentrancy-guard\" class=\"code-line\" dir=\"auto\" data-line=\"303\">Reentrancy-guard<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"305\">Reentrancy guards provide additional protection against this type of attack.<\/p>\n<h3 id=\"after-the-external-call-check-the-value-before-writing\" class=\"code-line\" dir=\"auto\" data-line=\"307\">Post-external call verification<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"309\">You can verify the value of <code class=\"codehl\">tokenIds<\/code>\u00a0after the\u00a0<code class=\"codehl\">_safeMint<\/code> function call completes and revert the transaction if <code class=\"codehl\">tokenIds<\/code> changed unexpectedly, however this approach adds complexity.<\/p>\n<h2 id=\"conclusion\" class=\"code-line\" dir=\"auto\" data-line=\"314\">Conclusion<\/h2>\n<p class=\"code-line code-active-line\" dir=\"auto\" data-line=\"316\">It is critical to be aware of external calls in functions, because these create doors for reentrancy attacks. Always consider what functions might be triggered during these external calls.<\/p>\n<p dir=\"auto\" data-line=\"316\"><span style=\"font-weight: 400;\">For more examples, read our <a title=\"Reentrancy Examples Github Repository\" href=\"https:\/\/github.com\/Ackee-Blockchain\/reentrancy-examples\">Reentrancy Examples Github Repository<\/a>. There are other types of reentrancy attacks and also protocol-specific reentrancies, and our blog features deep dives on some of these as well.<\/span><\/p>\n<ul>\n<li dir=\"auto\" data-line=\"4\"><a href=\"https:\/\/ackee.xyz\/blog\/single-function-reentrancy-attack\/\" target=\"_blank\" rel=\"noopener\">Single Function Reentrancy Attack<\/a><\/li>\n<li dir=\"auto\" data-line=\"4\"><a href=\"https:\/\/ackee.xyz\/blog\/cross-function-reentrancy-attack\/\" target=\"_blank\" rel=\"noopener\">Cross Function Reentrancy Attack<\/a><\/li>\n<li dir=\"auto\" data-line=\"4\"><a href=\"https:\/\/ackee.xyz\/blog\/cross-contract-reentrancy-attack\/\" target=\"_blank\" rel=\"noopener\">Cross Contract Reentrancy Attack<\/a><\/li>\n<li dir=\"auto\" data-line=\"4\"><a href=\"https:\/\/ackee.xyz\/blog\/read-only-reentrancy-attack\/\" target=\"_blank\" rel=\"noopener\">Read Only Reentrancy Attack<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>A cross-chain reentrancy attack is an exploit that targets smart contract function calls across different chains, and can lead to loss of funds in the smart contract. Learn more about this vulnerability with examples to ensure your code doesn&#8217;t leave open doors to attackers. The vulnerability Events emitted at inappropriate locations in code can create cross-chain reentrancy vulnerabilities. Such an event could&hellip;<\/p>\n","protected":false},"author":24,"featured_media":1016,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[61,10,84,103],"tags":[24,138,64],"class_list":["post-802","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-education","category-ethereum","category-hacks","category-wake","tag-ethereum","tag-reentrancy-attack","tag-security"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/03\/Cross-Function-Reentrancy-Attack-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/03\/Cross-Function-Reentrancy-Attack-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\/802","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=802"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/802\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/1016"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=802"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=802"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=802"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}