The deposit() function in Staking contract transfers the specified TKN amount from the msg.sender to the contract. The problem is the return value of this operation is never checked. Some tokens do not revert on transfer failure, but return false instead. This creates the possibility for the attacker to steal all of the TKNs from the Staking contract.
The deposit() method looks like this:
The return value of the transferFrom method is never checked, so the following scenario is possible:
Attacker notices a Staking contract where 1 million TKNs have been deposited. The TKN is a token that does not revert on failure.
The attacker calls the deposit() function with the _amount of 1 million. The attacker does not have enough TKNs so the transfer will fail, but since the return value is never checked, the balances[msg.sender] will be updated to 1 million.
The attacker calls the withdraw() method, stealing the 1 milltion TKNs from the contract.
The attacker can steal all of the TKNs from the contract. This requires the TKN to be a token that does not revert on failure.
The unsafe ERC20 operations have been reported in the known issues section under low category, however this particular exploitation of them is a separate, high-risk issue.
Manual Review
Replace the transfer/transferFrom calls with the OpenZeppelin safeTransfer/safeTransferFrom.
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.