A critical vulnerability exists in the _splitRewards
function of the LSTRewardsSplitter contract, where the lack of reentrancy protection allows an attacker to perform a reentrancy attack. This attack enables the attacker to repeatedly invoke the _splitRewards
function during the execution of a token transfer, potentially leading to the unintended burning of user rewards or a denial-of-service (DoS) condition. The vulnerability arises from the use of an ERC777 token (lst
) and the absence of safeguards against reentrancy in functions that perform external calls.
Reentrancy Risk: The _splitRewards
function makes external calls to lst.safeTransfer
and IStakingPool(address(lst)).burn
without any reentrancy protection such as the nonReentrant
modifier.
ERC777 TokensReceived Hook: The lst
token is likely an ERC777 token, which triggers the tokensReceived
hook on the recipient contract whenever tokens are transferred. This allows a recipient contract to execute code during the transfer process.
Fee Receiver as Malicious Contract: An attacker can set a fee receiver to be a malicious contract that implements the tokensReceived
function. Within this function, the attacker can re-enter the _splitRewards
function by calling splitRewards()
again.
Setup:
The attacker deploys a malicious contract that implements the tokensReceived
function. This function will call the splitRewards
function on the LSTRewardsSplitter
contract when it receives tokens.
The attacker gets this contract added as a fee receiver in the fees
array of the LSTRewardsSplitter
contract, potentially by social engineering the contract owner or exploiting any insufficient access controls.
Execution:
When _splitRewards
is called, and it reaches the lst.safeTransfer(fee.receiver, amount);
line, the tokensReceived
function on the attacker's contract is triggered due to the ERC777 token standard.
Inside tokensReceived
, the attacker calls splitRewards()
again.
This reentrancy causes _splitRewards
to execute again before the first execution has completed.
Impact:
Infinite Loop / Stack Depth Limit: The recursive calls can lead to an infinite loop or reach the EVM's call stack depth limit, causing the transaction to fail.
Denial of Service: Legitimate users are unable to receive their rewards because the transaction reverts or consumes excessive gas.
Burning Excessive Tokens: If the burn
function is called multiple times due to reentrancy, more tokens than intended may be burned, reducing the total supply and harming token holders.
Denial of Service (DoS): The reentrancy attack can prevent the successful execution of the _splitRewards
function, blocking reward distribution to all users.
Unintended Token Burning: Excessive or unintended burning of LST tokens reduces the total supply, adversely affecting the value of tokens held by users.
Financial Loss: Users may suffer financial losses due to the decreased value of their holdings or inability to access their rewards.
Loss of Trust: Exploitation of this vulnerability undermines confidence in the smart contract's security and the platform's reliability.
Manual Code Review: Careful examination of the smart contract code to identify potential vulnerabilities.
Solidity Documentation: Understanding of the ERC777 token standard and its tokensReceived
hook.
Security Analysis Tools: Utilization of static analysis tools like Slither or MythX to detect reentrancy vulnerabilities.
Testing Frameworks: Using frameworks like Truffle or Hardhat to simulate the attack scenario in a controlled environment.
Implement Reentrancy Guards:
Use ReentrancyGuard
: Import OpenZeppelin's ReentrancyGuard
contract and apply the nonReentrant
modifier to the _splitRewards
function and any other functions that make external calls and modify state.
Update State Variables Before External Calls:
Adjust principalDeposits
Early: Update critical state variables like principalDeposits
before making any external calls to prevent state inconsistencies during reentrancy.
Limit or Validate Fee Receivers:
Disallow Contracts as Fee Receivers: Ensure that fee receivers are not contracts, or if they are, that they do not implement malicious behavior.
Validate Addresses: Implement checks to prevent adding the LST token address or other sensitive addresses as fee receivers.
Use Safe Transfer Methods Appropriately:
Avoid Using safeTransfer
with ERC777 Tokens: Since safeTransfer
can trigger the tokensReceived
hook, consider using transfer
or a lower-level call when transferring ERC777 tokens, while ensuring compliance with the token standard.
Implement Pull Over Push Mechanism:
Pull Payments: Instead of pushing tokens to fee receivers, update their balances and allow them to withdraw funds themselves. This minimizes external calls within critical functions.
Limit the Size of Loops:
Cap Fees Array Length: Set an upper limit on the number of fee receivers to prevent unbounded loops that can lead to DoS due to gas limits.
Thorough Testing and Auditing:
Security Audits: Engage professional auditors to review the smart contracts for vulnerabilities.
Comprehensive Testing: Write unit tests and integration tests that simulate attack scenarios, including reentrancy attacks.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.