Rock Paper Scissors

First Flight #38
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Invalid

Missing Access Control on Token Burn Function

Summary

The WinningToken contract inherits from OpenZeppelin's ERC20Burnable but doesn't override the burn functionality with appropriate access controls. This allows any token holder to burn their tokens, which contradicts the intended design of a controlled game token system where token lifecycle should be managed by the game contract.

Vulnerability Details

The WinningToken contract implements:

contract WinningToken is ERC20, ERC20Burnable, Ownable {
// No override of burn() or burnFrom() functions
}

By inheriting from ERC20Burnable without overriding the functions, the contract inherits:

  • burn(uint256 amount) - allowing any user to burn their own tokens

  • burnFrom(address account, uint256 amount) - allowing approved addresses to burn tokens from others

Since the intent appears to be that only the owner (the game contract) should control token lifecycle, this unrestricted burning capability goes against the token's design purpose.

Impact

This vulnerability allows any player to unilaterally destroy their tokens rather than using them within the game system. This can lead to:

  1. Circumvention of game economics - Players can burn tokens instead of using them in the game

  2. Inconsistent token accounting - The game contract may lose track of tokens that were intended to be in circulation

  3. Potential game state manipulation - If the game contract doesn't account for tokens being burned outside its control, this could lead to unexpected behaviors

The severity is medium since this doesn't directly lead to fund loss but undermines the token economy design and could disrupt game functionality.

Tools Used

Manual code review

Recommendations

Implement access control on burn operations by overriding the burn functions:

/**
* @dev Override burn function to restrict access to owner only
* @param amount The amount of tokens to burn
*/
function burn(uint256 amount) public virtual override onlyOwner {
super.burn(amount);
}
/**
* @dev Override burnFrom function to restrict access to owner only
* @param account The account whose tokens will be burned
* @param amount The amount of tokens to burn
*/
function burnFrom(address account, uint256 amount) public virtual override onlyOwner {
super.burnFrom(account, amount);
}

Alternatively, if the intent is to allow the game contract to burn tokens while also allowing players to burn their own tokens:

  1. Create a mapping of authorized burners:

mapping(address => bool) public authorizedBurners;
  1. Add functions to manage this list:

function addAuthorizedBurner(address burner) external onlyOwner {
authorizedBurners[burner] = true;
}
function removeAuthorizedBurner(address burner) external onlyOwner {
authorizedBurners[burner] = false;
}
  1. Override burn functions with this check:

function burn(uint256 amount) public virtual override {
require(msg.sender == owner() || authorizedBurners[msg.sender], "Not authorized to burn");
super.burn(amount);
}
function burnFrom(address account, uint256 amount) public virtual override {
require(msg.sender == owner() || authorizedBurners[msg.sender], "Not authorized to burn");
super.burnFrom(account, amount);
}

This ensures only authorized entities can perform token burning operations.

Updates

Appeal created

m3dython Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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