_transfer in ERC20Internals.sol loads the recipient balance (toAmount) and then stores add(toAmount, value) without bounding the sum.
Because the yul add opcode wraps on overflow, any transfer that drives toAmount + value >= 2^256 silently wraps to the modulo result. If the recipient had a non-zero balance, the wrap typically sets their stored balance to zero while emitting a Transfer event that claims the victim was credited with an enormous amount. Attackers can obtain near-type(uint256).max balances through the public mint helper, and then forward those tokens to any target with a dust balance to trigger the overflow.
An attacker can zero out arbitrary users’ balances, griefing them permanently because the storage slot now holds 0 even though downstream systems saw a gigantic Transfer event. Integrations that rely on Transfer logs for accounting (bridges, indexers, lending markets) are fed false data, enabling theft or incorrect solvency calculations. As soon as a single EOA or contract holds near the uint256 limit (highly likely in this implementation), every other holder can be rugged.
Deploy Token from test/Token.sol.
Mint type(uint256).max tokens to attacker A and 1 token to victim V (both balances are permitted because _mint also lacks overflow checks).
Have A call transfer(V, type(uint256).max).
_transfer subtracts the amount from A, but add(1, type(uint256).max) wraps to 0, so V’s balance becomes zero while the Transfer event reports an inbound deposit of type(uint256).max.
This behavior is reproduced and asserted in test/TransferOverflow.t.sol:test_transferRecipientOverflowResetsVictimBalance().
Before writing the recipient balance, ensure value <= type(uint256).max - toAmount (or revert with ERC20InsufficientBalance). The simplest fix is to move the logic into Solidity so that toAmount + value triggers the built-in checked arithmetic revert on overflow.
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.
The contest is complete and the rewards are being distributed.