Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: medium
Invalid

Tokens can be stolen by front-running initialization of Streets contract in CredToken

Summary

A large amount of CredTokens can be minted by calling CredToken::mint after CredToken contract deployment, but prior to deployment script's call to CredToken::setStreetsContract

Vulnerability Details

The private storage variable _streetsContract in CredToken has a default value of 0 since it is of address type. An attacker can take advantage of this default value by calling CredToken::mint using address(0) in a very specific timeframe between the deployment of the CredToken contract and the calling of CredToken::setStreetsContract within a deployment script. The attack would consist of minting maximum possible amount of CredTokens as address(0) and then transfering them to another address.

Note: This vulnerability also exists for the OneShot contract, but the only impact is that an attacker using address(0) could call OneShot::updateRapperStats function, which would be minimal impact.

Severity

Severity is judged as Medium, with impact being High and likelihood being hard to evaluate as a deployment script was not provided and therefore could not be examined for proper deployment of the OneShot set of smart contracts.

Tools Used

Visual Studio Code, Foundry, manual review

Proof of Code

To show how this attack could be executed, take the following steps.

1 . To simulate the uninitialized pre-condition needed for the attack, alter OneShotTest::setUp to not call CredToken::setStreetsContract

function setUp() public {
oneShot = new OneShot();
cred = new Credibility();
streets = new Streets(address(oneShot), address(cred));
rapBattle = new RapBattle(address(oneShot), address(cred));
user = makeAddr("Alice");
challenger = makeAddr("Slim Shady");
oneShot.setStreetsContract(address(streets));
- cred.setStreetsContract(address(streets));
+ // cred.setStreetsContract(address(streets));
}
  1. Add the following test function to OneShotTest:

function testUninitializedStreetInCredToken() public {
// prank as zero address
vm.startPrank(address(0));
// setup receiving address
address whaleToBe = makeAddr("BizMarkie");
// mint as much as possible
uint256 amountToMint = type(uint256).max - cred.totalSupply() - 1;
cred.mint(whaleToBe, amountToMint);
// validate receiving address has the expected amount
assert(cred.balanceOf(whaleToBe) == amountToMint);
}
  1. Execute the test and see that it passes - meaning that all possible CredTokens have been minted and sent to the attacker's intended recipient address.

Recommendations

It is recommended to place a check in CredToken::mint for address(0) as shown below:

function mint(address to, uint256 amount) public onlyStreetContract {
+ require(
+ msg.sender != address(0),
+ "Caller may not be address(0) - Streets contract must be initialized"
+ );
_mint(to, amount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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