# ZRC20 Token Pause Check Bypass

ZetaChain's ZRC20 pause check runs in Ethermint hooks after zEVM calls, so a contract's onCrossChainCall can withdraw a paused token.

- Payout: Contest reward
- Severity: medium
- Program: ZetaChain
- Credited: ChristiansWhoHack
- Disclosed: 2024-09-06
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-11-zetachain-findings/issues/333
- Library page: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-26
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:evm technique:chained technique:source-review vuln:access-control vuln:business-logic

**Target:** ZRC20 token pause enforcement in crosschain module zEVM calls
**Root cause:** Pause enforcement lives in Ethermint post-tx hooks (fungible module) rather than in the ZRC20 contract or the crosschain module's zEVM call path; crosschain module calls into zEVM below the hook execution point and never calls CheckZRC20Paused.
**Steps:**
1. Deploy a ZRC20 token via DeployZRC20Contract and set its ForeignCoins.Paused = true (as MsgUpdateZRC20PausedStatus does).
2. Deploy attacker contract implementing onCrossChainCall that calls `token.approve(address(token), max)` then `token.withdraw(abi.encodePacked(attacker), 1)`.
3. Submit `MsgVoteOnObservedInboundTx` with Receiver = attacker contract, triggering the crosschain module to call onCrossChainCall on zEVM.
4. Observe the zEVM call and withdrawal succeed despite the token being paused.
**How found:** Code reading of Ethermint hook placement: noticed crosschain module calls into zEVM below where hooks run, and that processLogs is called without CheckZRC20Paused, hypothesizing the pause check could be skipped via the onCrossChainCall callback.
**Exploitation:** Attacker deploys a contract whose onCrossChainCall callback invokes ZRC20.withdraw on a paused token; because the crosschain module's zEVM call path skips the fungible module's pause hook, the withdrawal is processed and an outbound CCTX is created, defeating the emergency pause protection.
**Insight:** When a safety check is implemented as a post-execution hook rather than inline in the call path, enumerate every entrypoint that reaches the guarded action below the hook (here, crosschain module zEVM calls) and test each with a callback contract.
