Description:
The Token.sol test contract exposes mint() and burn() functions as public without any access control. While this may be intentional for testing, if used as a base for production contracts, it represents a critical vulnerability where anyone can arbitrarily mint or burn tokens.
contract Token is ERC20 {
constructor() ERC20("Token", "TKN") {}
function mint(address account, uint256 value) public {
_mint(account, value);
}
function burn(address account, uint256 value) public {
_burn(account, value);
}
}
Impact:
Unlimited Token Creation: Any address can mint unlimited tokens, destroying the token's economic value.
Unauthorized Token Destruction: Any address can burn tokens from any account, stealing value from users.
Complete Loss of Token Economics: The token becomes worthless and unusable for any serious application.
Proof of Concept:
function test_AnyoneCanMint() public {
address attacker = makeAddr("attacker");
address victim = makeAddr("victim");
vm.prank(attacker);
token.mint(attacker, 1000000e18);
assertEq(token.balanceOf(attacker), 1000000e18);
}
function test_AnyoneCanBurnFromAnyAccount() public {
address victim = makeAddr("victim");
address attacker = makeAddr("attacker");
token.mint(victim, 100e18);
assertEq(token.balanceOf(victim), 100e18);
vm.prank(attacker);
token.burn(victim, 100e18);
assertEq(token.balanceOf(victim), 0);
}
Mitigation:
Implement proper access control using OpenZeppelin's Ownable or AccessControl:
pragma solidity ^0.8.24;
import {ERC20} from "./ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract Token is ERC20, Ownable {
constructor() ERC20("Token", "TKN") Ownable(msg.sender) {}
function mint(address account, uint256 value) public onlyOwner {
_mint(account, value);
}
function burn(address account, uint256 value) public onlyOwner {
_burn(account, value);
}
}