Summary
SDLPool.addToken()
lacks a safety mechanism to prevent the same token from being added multiple times.
Vulnerability Details
There's no safety check in SDLPool.addToken()
. There's a possible exploit scenario that might happen:
One token being added twice in the rewards pool. The token would be counted doubly in the mapping(address => IRewardsPool) public tokenPools;.
File : contracts/core/sdlPool/base/SDLPool.sol
336: function addToken(address _token, address _rewardsPool) public override onlyOwner {
337: if (_token == address(sdlToken)) revert InvalidToken();
338: super.addToken(_token, _rewardsPool);
339: }
https://github.com/Cyfrin/2023-12-stake-link/blob/549b2b8c4a5b841686fceb9c311dca9ac58225df/contracts/core/sdlPool/base/SDLPool.sol#L336-L339
Proof of Concept
This scenario is illustrated in a minimalist example, which you can use in Remix:
pragma solidity 0.8.15;
contract SimpleTokenPool {
address[] public tokens;
address public owner;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
function addToken(address _token) public onlyOwner {
tokens.push(_token);
}
function isTokenAdded(address _token) public view returns (bool) {
for (uint i = 0; i < tokens.length; i++) {
if (tokens[i] == _token) {
return true;
}
}
return false;
}
}
Impact
Adding the same token twice would not raise any error here. I consider this a high-risk issue.
Tools Used
Recommendations
This behaviour can be mitigated by implementing the following require()
statement:
+ mapping(address => bool) private _tokenRegistry;
...
function addToken(address _token, address _rewardsPool) public override onlyOwner {
+ require(!_tokenRegistry[_token], "Token already added");
+ _tokenRegistry[_token] = true;
if (_token == address(sdlToken)) revert InvalidToken();
super.addToken(_token, _rewardsPool);
}