# Holders array can be manipulated by transferring or burning with amount 0, stealing rewards or bricking certain functions

Zero-amount transfers/burns bypass the balanceOf!=0 check in _beforeTokenTransfer, letting attackers duplicate or zero-address entries in the holders array to steal rewards or DoS distribution.

- Payout: Contest reward
- Severity: high
- Program: Althea Liquid Infrastructure
- Credited: BowTiedOriole
- Disclosed: 2024-04-08
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2024-02-althea-liquid-infrastructure-findings/issues/77
- Library page: https://bugbountylibrary.com/r/c4%3A2024-02-althea-liquid-infrastructure%3AH-01
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:business-logic vuln:dos vuln:reward-distribution

**Target:** LiquidInfrastructureERC20 ERC20 reward-distribution contract
**Root cause:** _beforeTokenTransfer pushes `to` into holders whenever balanceOf(to)==0, but zero-amount transfers and burns (to==address(0)) also satisfy this, so the same address or the zero address can be appended repeatedly.
**Steps:**
1. Get approved as holder via approveHolder.
2. Call `transferFrom(OTHER_ADDRESS, self, 0)` repeatedly to append self to holders array multiple times.
3. Mint balances and withdrawFromAllManagedNFTs to fund distribution.
4. Call `distribute(2)` so the loop hits the duplicated holder twice, sending all entitlement to attacker while distributeToAllHolders reverts.
5. Alternatively call `burn(0)` repeatedly to push address(0) into holders, bloating the array and bricking distributeToAllHolders.
**How found:** Code review of _beforeTokenTransfer's holder-registration logic: noticed the existence check uses balanceOf(to)!=0 rather than tracking membership, and that ERC20 permits amount==0 transfers/burns, making the check bypassable.
**Exploitation:** Attacker duplicates their own entry in holders, then triggers distribute() with a limit covering both duplicate slots; the loop pays entitlement based on balanceOf(recipient) each iteration, so the attacker collects rewards twice while honest holders get nothing and distributeToAllHolders reverts.
**Escalation:** Repeated zero-amount transfers scale the duplication arbitrarily; zero-address burns grow the array unboundedly to permanently DoS distribution.
**Insight:** When a contract maintains a membership array keyed on a balance check, test whether zero-value transfers, self-transfers, or burns to address(0) can re-trigger the append; balance-based existence checks are not membership checks.
