Beginner FriendlyFoundryBridge
100 EXP
View results
Submission Details
Severity: low
Valid

`s_tokenToAddress` mapping not checking if there is a token with specific symbol already deployed leads to possible token overwrites

Summary

There isn't any kind of checks to stop the token factory owner from accidentally (or by being a victim of social engineering) deploying another token with same symbol as an already deployed token.

Details

In TokenFactory contract, s_tokenToAddress uses token symbol as keys for the mapping. When a new token is stored to the mapping there are no checks if a token already has been deployed with the same symbol.

The address of the token will be overwritten with the new token's address and the old token's address will not be in the mapping anymore.

Filename

src/TokenFactory.sol

Permalinks

https://github.com/Cyfrin/2023-11-Boss-Bridge/blob/dad104a9f481aace15a550cf3113e81ad6bdf061/src/TokenFactory.sol#L27C16-L27C16

Impact

Tokens that were deployed in the past will not show as deployed anymore since they will not be in s_tokenToAddress mapping.

Recommendations

Have a check to see if a token with that symbol was already deployed. If yes, do not deploy it again as this would overwrite the existing entry in s_tokenToAddress mapping.

There could be valid reasons to update an address of a deployed token. Updating an address should be a deliberate action and a new function could be created that would update an address of an already deployed token.

function deployToken(string memory symbol, bytes memory contractBytecode) public onlyOwner returns (address addr) {
+ if (s_tokenToAddress[symbol] != address(0)){
+ revert("token already deployed");
+ }
assembly {
addr := create(0, add(contractBytecode, 0x20), mload(contractBytecode))
}
s_tokenToAddress[symbol] = addr;
emit TokenDeployed(symbol, addr);
}

Tools Used

  • Manual Audit

  • Foundry

POC

New copy of L1Token is created my malicious actor

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract L1TokenCopy is ERC20 {
uint256 private constant INITIAL_SUPPLY = 1_000_000;
constructor() ERC20("BossBridgeTokenCopy", "BBTC") {
_mint(msg.sender, INITIAL_SUPPLY * 10 ** decimals());
}
}

Token deployed with same symbol as an already-deployed token

import { L1TokenCopy } from "../src/L1TokenCopy.sol";
// ...
function testTokenOverwritten() public {
// token factory owner deployes a new token
vm.prank(owner);
address tokenAddress = tokenFactory.deployToken("UberToken", type(L1Token).creationCode);
assertEq(tokenFactory.getTokenAddressFromSymbol("UberToken"), tokenAddress);
// attacker sees this and creates a new L1 token with same symbol
// token factory owner deploys again - either by mistake or through social engineering by the attacker
// there are no checks to prevent or warn the owner that a token with that symbol is already deployed
vm.prank(owner);
address maliciousTokenAddress = tokenFactory.deployToken("UberToken", type(L1TokenCopy).creationCode);
assertNotEq(tokenAddress, maliciousTokenAddress);
assertEq(tokenFactory.getTokenAddressFromSymbol("UberToken"), maliciousTokenAddress);
}
Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

deployToken: non-unique symbol for tokens

Support

FAQs

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