# Incorrect genesis initialization of pending nonces

ZetaChain's crosschain InitGenesis resets pending nonces to 0, so after a hard reset or fork UpdateNonce errors and cctxs can never be processed.

- Payout: Contest reward
- Severity: medium
- Program: ZetaChain
- Credited: berndartmueller
- Disclosed: 2024-09-06
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-11-zetachain-findings/issues/389
- Library page: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-23
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:code4rena sev:medium tech:go technique:source-review vuln:business-logic vuln:dos

**Target:** Cosmos SDK x/crosschain module InitGenesis/UpdateNonce
**Root cause:** InitGenesis sets PendingNonces NonceLow/NonceHigh to 0 for all default chains instead of restoring real pending nonces, while ChainNonces are restored non-zero; UpdateNonce then fails the NonceHigh == nonce.Nonce check.
**Steps:**
1. Note InitGenesis sets PendingNonces{NonceLow:0,NonceHigh:0} for each default chain while ChainNoncesList restores real non-zero nonces.
2. Simulate genesis with a chain nonce of 2 via sample.ChainNonces(t, "2").
3. Call crosschain.InitGenesis then GetPendingNonces for that chain.
4. Observe NonceHigh == 0 instead of 2, so UpdateNonce returns ErrNonceMismatch.
**How found:** Code review of genesis.go: noticed ChainNonces restored from exported state but PendingNonces hardcoded to 0, then traced UpdateNonce's NonceHigh equality check and its callers.
**Exploitation:** Not attacker-triggered; occurs on node hard-reset or hard fork. After genesis, any UpdateNonce call (EVM PostTxProcessing hook, inbound/outbound cctx refunds, cross-chain messaging, TSS fund migration, ERC-20 whitelist) errors, reverting EVM txs and aborting cctxs without refund; no on-chain recovery path exists.
**Escalation:** Single root cause propagates to six call sites, causing stuck cross-chain transactions and unrefunded funds chain-wide.
**Insight:** When auditing genesis/init code, diff what ExportGenesis persists against what InitGenesis reconstructs; hardcoded zero defaults for counters that must match restored state silently break equality checks downstream.
