he issue lies in the order of operations within the updateFee
function. The function first updates the fee at the given index with the new receiver and fee basis points, and then it checks if the total fees exceed the maximum allowed limit (MAX_BASIS_POINTS
) using the _totalFeesBasisPoints
function. If the total fees exceed the limit, the function reverts with the FeesExceedLimit
error.
updateFee
function does not properly validate the total sum of fees after the update. It only checks if the total fees exceed the limit after the update, but it doesn't prevent the update from happening if the limit is exceeded.
This vulnerability can lead to a situation where the total fees exceed the maximum allowed limit (MAX_BASIS_POINTS
), potentially causing unexpected behavior or breaking the contract's invariants. https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/lstRewardsSplitter/LSTRewardsSplitter.sol#L151-L167
The updateFee
function is called with a specific index, receiver, and fee basis points.
The function updates the fee at the given index with the new receiver and fee basis points.
After the update, the function checks if the total fees exceed the MAX_BASIS_POINTS
limit by calling the _totalFeesBasisPoints
function.
If the total fees exceed the limit, the function reverts with the FeesExceedLimit
error.
However, the update has already been performed before the check, allowing the total fees to exceed the limit.
The issue occurs because the validation of the total fees is performed after the update, rather than before. This allows the update to be executed even if it would result in the total fees exceeding the maximum allowed limit.
Can be exploited by following these steps:
Initialize the LSTRewardsSplitter
contract with a set of fees that sum up to a value close to the MAX_BASIS_POINTS
limit.
Call the updateFee
function with an index of an existing fee and a new fee basis points value that, when added to the existing fees, exceeds the MAX_BASIS_POINTS
limit.
Observe that the updateFee
function allows the update to be executed, and the total fees exceed the limit.
Example scenario:
The contract is initialized with fees: [{ receiver: 0x123, basisPoints: 5000 }, { receiver: 0x456, basisPoints: 4000 }]
.
The updateFee
function is called with index = 0
, receiver = 0x789
, and feeBasisPoints = 6000
.
The function updates the fee at index 0 with the new receiver and fee basis points.
After the update, the total fees become 6000 + 4000 = 10000
, which exceeds the MAX_BASIS_POINTS
limit.
The function reverts with the FeesExceedLimit
error, but the update has already been applied.
The fact that the fee is updated before validating the total fees. This lines directly contribute to the vulnerability are: https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/lstRewardsSplitter/LSTRewardsSplitter.sol#L162-L164
Manual Review
Validate the total sum of fees before performing the update. If the total fees after the update would exceed the MAX_BASIS_POINTS
limit, the function should revert or prevent the update from happening.
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.