BABYFIDO Rug Pull

Reported loss $79K
Rugpull

What happened

BABYFIDO is an ERC20 token on Ethereum whose _transfer function hands every sender's balance to an external, unverified contract before checking it. The token has no owner and no setter, so the address of that helper contract is fixed at deployment, and whoever controls the helper's logic can decide what balance any sender appears to have. On 2023-11-14 at 04:16:47 UTC, address 0x45aF15b2…d7a448 swapped 2,200,000 BABYFIDO for about 39.43 WETH through the Uniswap Universal Router in transaction 0x1d492405…c0504a.

De.Fi's REKT database lists the incident as an exit scam/rugpull with a loss of 79,306 USD (39.42 WETH), and lists 0x7ccbeB78…Ae0Ab8 as a second address involved and the deployer 0x841DB643…cC8c7b. De.Fi's listing also says the proceeds were moved to another EOA and then used to add liquidity to a different token; that onward movement was not independently checked. The unverified helper's code is not public, so the sources do not show how the 2,200,000-token sale was able to drain the pool.

How it happened

**What the code allows**

  1. The deployment constructor passes its single argument to _mint(msg.sender, totalSupply_). Inside _mint, the first statement is _allowances[address(0)][address(0)] = amount;, which stores that argument in an allowance slot nobody can legitimately approve (_approve requires owner != address(0)). The next lines overwrite the local variable with amount = 420000000 * 10 ** 18;, so the argument never sets the supply; its only effect is the stored value. The Etherscan page for the deployment transaction shows the constructor argument 0x9ea8c16c…9ec14d.
  2. getTokens() reads that slot back as a contract address: return TOKEN(address(uint160(_allowances[address(0)][address(0)])));. The Etherscan code page for 0x9ea8c16c…9ec14d shows it as an unverified contract, so its turkey logic cannot be read.
  3. Every _transfer begins with _balances[from] = getTokens().turkey(from,_balances[from]);. The sender's stored balance is replaced by whatever number the helper returns, for any sender, including a holder selling or a liquidity pool paying out.
  4. The very next lines use that replaced value: uint256 fromBalance = _balances[from]; then require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");. A helper that returns a smaller number for a chosen sender makes that sender's transfer revert, which would block sells; a helper that returns a larger number lets a chosen sender move tokens it does not hold, without changing _totalSupply.
  5. The contract has no owner role, no renounceOwnership and no function that rewrites the slot, so the helper address cannot be changed or switched off after deployment. Everything the hook does depends on the helper's unpublished code.

**What happened**

  1. On 2023-11-14 at 04:16:47 UTC, address 0x45aF15b2…d7a448 sent 2,200,000 BABYFIDO to the Uniswap Universal Router and received about 39.43 WETH (Etherscan transaction page for 0x1d492405…c0504a). The 2,200,000 tokens sold are about 0.52% of the 420,000,000 supply. De.Fi's REKT database lists this as an exit scam/rugpull worth 79,306 USD.

Protocol details

Classification Token
Protocol Type Exit Scam/Rugpull
Affected asset / contract BABYFIDO

Build your security review skills

Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.