# Zero-address accounting corruption

Does address(0) alias a shared slot, get credited, or get zeroed mid-bookkeeping?

_Area: DeFi accounting and math bugs. Seen in 2 disclosed reports; latest 2023-07-17. Updated 2026-11-02._

## How it works
A contract treats address(0) as an ordinary key while also using it as a sentinel or shared slot. The assumption that "zero address is never a real account" breaks: operations on address(0) read or write the same storage that holds global state, or credit/debit a balance that no ownership check protects. The result is accounting that no longer matches reality — inflated shares, drained balances, or wiped history.

## Where it shows up
- A "global" singleton stored at `_accounts[address(0)]` while per-account operations also accept address(0) [E1](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-5.md)
- Config fields like `initialContributor`/recipient that accept address(0) without a guard [E2](https://bugbountylibrary.com/r/c4%3A2022-09-party%3AH-02.md)
- `burn`/`mint`/`transfer` paths with no zero-address ownership check, callable repeatedly [E2](https://bugbountylibrary.com/r/c4%3A2022-09-party%3AH-02.md)
- Ownership set to address(0) (via `_removeTokenFrom`) before delegation/checkpoint bookkeeping runs [E3](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-14.md)
- Save/load ordering where a local write can overwrite a global write to the same slot [E1](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-5.md)

## How to review
- For every mapping keyed by address, ask: can address(0) be passed here, and does it collide with a sentinel or global entry? The invariant: the global context and any per-account context must never resolve to the same storage slot.
- Trace `_loadContext`/`_saveContext` (or equivalent) ordering: if global is saved before local and both alias, the local write clobbers global [E1](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-5.md).
- Check every credit/debit path for address(0): is there an ownership check that actually fails for zero? A burn that "succeeds" on address(0) with no owned NFT can repeat [E2](https://bugbountylibrary.com/r/c4%3A2022-09-party%3AH-02.md).
- Check ordering of ownership mutation vs. bookkeeping: any `ownerOf` lookup after zeroing will misclassify the token [E3](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-14.md).

## How finders spotted it
- Read `_loadContext`, saw global is `_accounts[address(0)]`; noticed settling address(0) makes global and local identical, then traced `_settle`/`_saveContext` ordering to see the local write clobber the global one [E1](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-5.md).
- Read the burn path: `_burn` on address(0) has no ownership check preventing repeats, and `initialContributor=address(0)` is an accepted config; combined the two into a drain [E2](https://bugbountylibrary.com/r/c4%3A2022-09-party%3AH-02.md).
- Read the `moveTokenDelegates` cleanup loop alongside `transferFrom` ordering: `_removeTokenFrom` zeroes owner before the delegation update, so the inequality is always true for the moved token [E3](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-14.md).

## Variants seen
- Global/local context aliasing at address(0), inflating global assets/shares [E1](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-5.md)
- Repeated burn of a zero-address initial contribution draining ETH [E2](https://bugbountylibrary.com/r/c4%3A2022-09-party%3AH-02.md)
- Owner zeroed mid-transfer causing checkpoint cleanup to wipe delegation history [E3](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-14.md)

## Impact and severity
Accounting corruption: inflated global assets/shares [E1](https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-5.md), full drain of contributed ETH [E2](https://bugbountylibrary.com/r/c4%3A2022-09-party%3AH-02.md), and corrupted delegation/checkpoint history [E3](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-14.md). Impact rises when the zero address is reachable through normal config or user calls and when the corrupted state is global, so one call scales across all accounts.

## Evidence
- E1: https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AH-5.md
- E2: https://bugbountylibrary.com/r/c4%3A2022-09-party%3AH-02.md
- E3: https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-14.md
