A critical flaw in the Sorra staking contract allowed an attacker to repeatedly withdraw the same rewards, draining 3M SOR tokens. Here’s how it happened.
On January 4, 2025, the Sorra
Staking contract was exploited due to flawed logic in the getPendingRewards() function, which failed to track and deduct previously distributed rewards, enabling repeated withdrawals of the same rewards. The attacker, who had deposited 122,868 SOR tokens on December 21, 2024, exploited this flaw to drain 3,071,721 SOR tokens and profit approximately $41,000.
On January 4, 2025, the Sorra staking contract was exploited due to flawed logic that did not account for whether the user had already withdrawn their rewards. This highlights how even seemingly straightforward mechanisms, like those in a prime number staking contract—can become vulnerable without proper validation checks.
The attacker prepared for this attack by depositing 122,868 SOR tokens into the staking contract 14 days earlier, on December 21, 2024, and selecting a lockup period of 14 days.
The attacker took advantage of the getPendingRewards()
function, which failed to properly track and deduct previously distributed rewards, allowing repeated withdrawals of the same rewards.
As a result, the attacker repeatedly called the withdraw()
function, ultimately draining 3,071,721 SOR tokens and profiting approximately $41,000.
Attacker Address: 0xdc8076
Attack Transaction: 0x6439d
Vulnerable Contract: 0x5d16b
The attacker prepared for the exploit on December 21, 2024, by depositing 122,868 SOR tokens into the staking contract.
According to the contract logic, the lockup periods vary by tier: tier 0 requires a 14-day wait, tier 1 requires 30 days, and tier 2 requires 60 days. The attacker chose tier 0, resulting in a 14-day lockup period.
On January 4, 2025 (exactly 14 days after the deposit), the attacker initiated the exploit by calling the withdraw()
function.
The withdraw()
function allows users to withdraw a specified _amount
of their staked tokens, calculates and distributes any pending rewards, updates the user's position, and transfers both the staked tokens and rewards (if applicable) to the user.
The getPendingRewards() function calculates the pending rewards for the msg.sender. In this case, it returned 6,143 SOR tokens.
When rewardAmount > 0
, the contract updates userRewardsDistributed[_msgSender()]
with the rewardAmount
. However, due to a flaw in the logic, the calculation of the user's pending rewards does not properly account for the userRewardsDistributed[_msgSender()]
.
This oversight means there is no record or proof that the user has already withdrawn their rewards. As a result, the attacker was able to repeatedly call the withdraw()
function with 1 Wei token.
The attacker ultimately withdrew 3,071,721 SOR tokens through repeated calls and swapped them on UniswapV2, profiting approximately $41,000.
The root cause of the exploit lies in the flawed reward distribution logic in the withdraw()
function. Specifically, the calculation of pending rewards in getPendingRewards()
did not properly account for userRewardsDistributed[_msgSender()]
, allowing the same rewards to be withdrawn repeatedly. This oversight enabled the attacker to exploit the contract by repeatedly calling withdraw()
to claim excessive rewards and profit significantly.
Take a look at the funds flow and track how the stolen tokens were moved across the blockchain.
getPendingRewards()
function should have accounted for the userRewardsDistributed[_msgSender()]
value when calculating pending rewards to ensure rewards are not double-counted.Contents
Get updates on our community, partners, events, and everything happening across the ecosystem — delivered straight to your inbox.
Subscribe Now!
Office 104/105 Level 1, Emaar Square, Building 4 Sheikh Mohammed Bin Rashid Boulevard Downtown Dubai, United Arab Emirates P.O box: 416654
Privacy PolicyAll Rights Reserved. © 2025. QuillAudits - LLC
Office 104/105 Level 1, Emaar Square, Building 4 Sheikh Mohammed Bin Rashid Boulevard Downtown Dubai, United Arab Emirates P.O box: 416654
audits@quillaudits.comAll Rights Reserved. © 2025. QuillAudits - LLC
Privacy Policy