Token-0x

First Flight #54
Beginner FriendlyDeFi
100 EXP
Submission Details
Impact: medium
Likelihood: high

Missing Access Control on mint() and burn() Functions

Author Revealed upon completion

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");
// Attacker can mint unlimited tokens to themselves
vm.prank(attacker);
token.mint(attacker, 1000000e18);
assertEq(token.balanceOf(attacker), 1000000e18);
}
function test_AnyoneCanBurnFromAnyAccount() public {
address victim = makeAddr("victim");
address attacker = makeAddr("attacker");
// Victim has tokens
token.mint(victim, 100e18);
assertEq(token.balanceOf(victim), 100e18);
// Attacker can burn victim's tokens
vm.prank(attacker);
token.burn(victim, 100e18);
assertEq(token.balanceOf(victim), 0);
}

Mitigation:
Implement proper access control using OpenZeppelin's Ownable or AccessControl:

// SPDX-License-Identifier: MIT
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);
}
}

Support

FAQs

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

Give us feedback!