Ultrasafe Honeypot
What happened
De.Fi's REKT database lists Ultrasafe (Usafe) on BNB Smart Chain as an Exit Scam/Honeypot and says the contract owner could disable the transfer function, which restricted users in selling their tokens. The verified source has no pause switch; the restriction comes from the burnTokenCheck modifier wrapped around every transfer and transferFrom. For a holder who is not whitelisted, the modifier lets tokens move only to the hard-coded _unirouter address 0x05fF2B0D…608C7F or to _owner, so a sale to any other address, such as a liquidity pair, reverts with an error message about the balance even though the balance is sufficient.
The owner can whitelist and blacklist addresses, can change _safeOwner, and can mint more supply. The source shows these powers exist; it does not show which of them were used.
How it happened
- The constructor stores the
ownerargument in both_ownerand_safeOwner.transferandtransferFromboth call_approveCheck, which is wrapped in theburnTokenCheckmodifier. - While
_owner == _safeOwner, the first transfer sent by the owner passes and runs_safeOwner = recipient;. From then on_safeOwneris whichever address received that transfer, and the owner can reassign it withdecreaseAllowance(address safeOwner). - Transfers pass when the sender is
_owneror_safeOwner, or when the recipient is_owner:if (sender == _owner || sender == _safeOwner || recipient == _owner). Senders in_whiteAddressalso pass. The owner fills that mapping throughmultiTransfer(the firstapprovecountreceivers) andincreaseAllowance(address[] memory receivers), which sets_whiteAddress[receivers[i]] = true. - Every other sender reaches the final branch.
_sellAmountstarts at 0, soamount < _sellAmountis false and the code runsrequire((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"). Becausesender == _safeOwnerwas already handled in step 3, such a holder can only send to_unirouteror_owner. A sale whose recipient is anything else reverts, and the revert message talks about balance even though_balances[sender]was never checked. addApprove(address[] memory receivers)lets the owner put any address in_blackAddress, which keeps that sender limited to_unirouter. If the owner sets_sellAmount(by sending tokens to itself once_safeOwnerdiffers from_owner), amounts below it pass, and when the recipient is_safeOwnerthe sender is added to_blackAddressand removed from_whiteAddress._mint(address account, uint256 amount)ispublicbut requiresmsg.sender == _ownerand credits_balances[_owner], so the owner can create more tokens. No function in the file changes_owner.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.