HACK ANALYSIS 4 min read

The Idols NFT Hack Analysis


The Idols NFT Hack Analysis

Overview:

On January 15, 2025, The Idols NFT (@TheIdolsNFT) contract on Ethereum suffered an exploit resulting in a loss of approximately $340K in stETH. The vulnerability originated from flawed logic in the _beforeTokenTransfer function that failed to handle reward claiming correctly when the sender and receiver were the same address. This allowed the attacker to repeatedly claim stETH rewards through carefully crafted transactions.

Smart Contract Hack Overview:

Fig: One of the Attack Transaction

Decoding the Smart Contract Vulnerability:

  • The root cause of the exploit was a flawed logic in the _beforeTokenTransfer function, which mishandled the claiming of rewards during NFT (ERC721 tokens) transfers when the sender (_from) and receiver (_to) were the same address. This logic oversight allowed the attacker to repeatedly claim stETH rewards by performing self-transfers.
Fig: _beforeTokenTransfer() Function
  • When _from and _to are the same, _beforeTokenTransfer first calls _claimEthRewards(_from) to claim pending stETH rewards for the sender. This action calculates the sender’s rewards and transfers them based on their current claimedSnapshots value. This uses the getPendingStethReward function, which calculates rewards as:(balanceOf(_user) * (rewardPerGod - claimedSnapshots[_user]))
Fig: getPendingStethReward() Function
  • After claiming the rewards, if the sender has no NFTs (ERC721 tokens) left after the transfer (balanceOf(_from) == 1), their claimedSnapshots entry is deleted. This reset removes the record of previously claimed rewards for the sender.
  • Since _from and _to are the same, _claimEthRewards(_to) is called next. At this point, claimedSnapshots[_to] has been either deleted or reset in the previous step. The reward calculation is repeated:(balanceOf(_to) * (rewardPerGod - 0)) from getPendingStethReward.
Fig: Vulnerable _claimEthRewards() Function
  • The subtraction of 0 (due to the deleted or reset claimedSnapshots) inflates the calculated rewards, enabling the same address to claim rewards again.
  • Inside _claimEthRewards, after transferring the current rewards, claimedSnapshots[_user] is reset to rewardPerGod. This reset makes it appear as though the user has not claimed rewards yet, allowing further exploitation in subsequent self-transfers. The reset occurs irrespective of whether the transfer involves a new receiver or the same address.
  • The attacker exploited this logic by repeatedly initiating self-transfers of NFTs (ERC721 tokens). Each iteration reset claimedSnapshots, enabling them to claim rewards anew in every transaction.

Attack Flow:

The attacker initiates an NFT transfer where _from == _to, triggering _beforeTokenTransfer.

_claimEthRewards is called for the sender (_from), and rewards are claimed based on the pending stETH balance.

claimedSnapshots[_from] is deleted due to the if(balanceOf(_from) == 1) check.

_claimEthRewards is called again for the receiver (_to), which is the same address as _from.

The attacker repeats this process in multiple transactions, draining stETH rewards.

  • The Idols NFT team has identified suspicious transactions on the Idols Main contract. The team is thoroughly exploring all available options to resolve the situation as quickly as possible and ensure the security of the project.
  • As a precautionary measure, the team advises users to refrain from interacting with any contracts related to the Idols NFT project until further notice to avoid potential risk. Further details: https://x.com/TheIdolsNFT/status/1879256089784635690

Mitigation and Best Practices:

  • Implement checks to prevent reward claims during self-transfers. If the sender and receiver are the same address, the reward claiming logic should be skipped to avoid multiple claims in a single transaction.
  • Refactor the logic that resets claimedSnapshots[_from] in the _beforeTokenTransfer function to only delete or reset the snapshot if the NFT is actually being transferred out (i.e., balanceOf(_from) == 1). Ensure that this reset does not occur during self-transfers, thereby preserving the integrity of the reward calculation and preventing rewards from being claimed multiple times by the same address.
  • Reward claims should be tied to specific actions that cause state changes, such as actual transfers of NFTs to different addresses. Ensure that rewards are only claimed when the recipient is a distinct address and not during self-transfers or no-op transactions.
  • To prevent such vulnerabilities, the best Smart Contract auditors must examine the Smart Contracts for logical issues. We at CredShields provide smart contract security and end-to-end security of web applications and externally exposed networks. Our public audit reports can be found on https://github.com/Credshields/audit-reports. Schedule a call at https://credshields.com/
  • Scan your Solidity contracts against the latest common security vulnerabilities with 280+ detections at SolidityScan.
Fig: SolidityScan — Smart Contract Vulnerability Scanner

Conclusion:

SolidityScan is an advanced smart contract scanning tool that discovers vulnerabilities and reduces risks in code. Request a security audit with us, and we will help you secure your smart contracts. Signup for a free trial at https://solidityscan.com/signup

Follow us on our Social Media for Web3 security-related updates.

SolidityScan — LinkedIn | Twitter | Telegram | Discord