ERC20Internals::_burn updates both totalSupply and balances[account] using unchecked sub in inline assembly without any prior balance or supply checks, so burning more tokens than the account balance or total supply causes both values to underflow to huge numbers, effectively minting tokens instead of reducing them.
Normal behavior: In a correct ERC-20 implementation, burn should reduce both totalSupply and the caller’s balance by value, and revert when value is greater than either the holder’s balance or the current totalSupply. This preserves the fundamental accounting invariant and prevents accidental or malicious over-burning.
Actual behavior: In ERC20Internals::_burn, the contract directly performs sub(supply, value) and sub(balance, value) in assembly and stores the result without any prior checks. When value exceeds totalSupply or the account’s balance, the subtraction wraps around at 2^256, causing both totalSupply and balances[account] to jump to extremely large values. This effectively mints a huge amount of tokens instead of burning, fully breaking ERC-20 accounting and enabling an attacker to escalate their balance to near-uint256 max with a single over-burn.
Likelihood:
The bug is triggered whenever a contract exposes _burn through a public or external function (e.g. burn(address,uint256) or burn(uint256)) and allows a caller to pass a value greater than their current balance or the token’s total supply. This is exactly how the provided Token test contract is wired, and it is a very common pattern for burnable ERC-20 tokens.
Any future integration or in-scope token that reuses this _burn implementation without adding explicit balance >= value and totalSupply >= value checks will immediately inherit the vulnerability, making the issue highly likely to manifest in practice as the codebase evolves.
Impact:
A malicious user can call the burn entrypoint with an oversized value to cause both totalSupply and their own balance to underflow to values close to type(uint256).max, effectively minting an enormous amount of tokens in a single transaction instead of burning.
With this artificially inflated balance and inflated totalSupply, the attacker can drain any pools, lending markets, or protocols that rely on this token’s balances and supply for pricing, collateral, rewards, or governance, leading to catastrophic and unrecoverable loss of funds and total loss of trust in the asset.
The following Foundry test demonstrates how calling burn with an amount larger than the holder’s balance causes both totalSupply and the attacker’s balance to increase due to unchecked underflow in _burn.
Just paste in test/Token.t.sol
Add explicit supply and balance checks in _burn before performing the sub operations in assembly, mirroring the safety pattern already used in _transfer and _spendAllowance. The function should revert when value exceeds either totalSupply or the account’s balance, and only then update storage.
missing checks for overflow and underflow.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.