asD
contract instances can be hijacked by attackers in case of a reorg and the interests earned in these contracts will be claimed by the attacker.
This protocol allows anyone to create asD
contract instances with the asDFactory.sol
. These instances are created with the new keyword without adding a salt, which means they are built with the create
opcode and the deployed addresses only depend on the nonce of the factory.
https://github.com/code-423n4/2023-11-canto/blob/335930cd53cf9a137504a57f1215be52c6d67cb3/asD/src/asDFactory.sol#L33C1-L38C6
file: asDFactory.sol
function create(string memory _name, string memory _symbol) external returns (address) {
--> asD createdToken = new asD(_name, _symbol, msg.sender, cNote, owner()); //@audit it doesn't use a salt. "_name" and "_symbol" also doesn't have to be uniqe.
isAsD[address(createdToken)] = true;
emit CreatedToken(address(createdToken), _symbol, _name, msg.sender);
return address(createdToken);
}
The second thing I would like to point out is that the _name
and the _symbol
don't have to be unique when creating asD
's. Reference in the Code4rena contest page:
"The asDFactory is used to create a new asD tokens. It only exposes a function create that accepts the name and symbol of the token to create. These do not have to be unique."
These two situations combined make the protocol vulnerable to reorgs, which can happen in any EVM chain.
-
Alice is an artist who plans to use
ERC1155tech
of this protocol for her NFT art project (note:ERC1155tech
protocol usesasD
as currency). -
Alice creates an
asD
contract, and uses this newly deployed contract's address in her art project as payment currency. -
Bob sees a network reorg happens and creates an
asD
token with the same name and the same symbol. -
Bob's transaction is executed first, and now Bob is the owner of the
asD
contract, which is deployed in the same address that Alice already started to use. -
Alice's transaction to create
asD
executes after Bob's but does not revert as the name and the symbol doesn't have to be unique. -
Alice's
asD
instance is different than her previous one, but she can't be aware of this because
- Her transaction didn't revert and she didn't get alarmed
- Everything is the same except the owner. The sameasD
address, the same_name
, and the same_symbol
. There is nothing to be suspicious about. -
Alice's art collection reaches good volumes and her
asD
contract earns interest. However, she can not withdraw these as she is not the actual owner of thatasD
contract.
Manual review
I would recommend using the new keyword with a salt derived from the msg.sender
For example:
function create(string memory _name, string memory _symbol) external returns (address) {
+ bytes32 salt = keccak256(abi.encode(msg.sender));
// Added salt during creation
+ asD createdToken = new asD{salt: salt}(_name, _symbol, msg.sender, cNote, owner());
isAsD[address(createdToken)] = true;
emit CreatedToken(address(createdToken), _symbol, _name, msg.sender);
return address(createdToken);
}
Note: The original submission can be found here.