# BlockBeforeSend hook can be exploited to perform a denial of service

Tokenfactory BeforeSendHook set to a non-contract address makes all transfers of that denom fail, blocking staking reward withdrawals and enabling chain halt via slashing.

- Payout: Audit contest
- Severity: high
- Program: MANTRA
- Credited: OakSecurity
- Disclosed: 2025-03-31
- Write-up quality: 8/10
- Original: https://code4rena.com/reports/2024-11-mantra-chain#h-01
- Library page: https://bugbountylibrary.com/r/c4%3A2024-11-mantra-chain%3AH-01
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:access-control vuln:business-logic vuln:dos

**Target:** Cosmos SDK tokenfactory module / staking & distribution hooks
**Root cause:** MsgSetBeforeSendHook lets any denom creator point the hook at an arbitrary address; the Sudo call then fails with 'no such contract', and since staking/distribution paths (withdrawDelegationRewards via BeforeDelegationSharesModified) must transfer the denom, the error propagates and aborts the operation.
**Steps:**
1. Create denom via `tokenfactory create-denom foo` and mint tokens to self
2. Deposit minted denom into validator rewards pool via `distribution fund-validator-rewards-pool $VAL 10000$DENOM` so pending rewards include it
3. Call `tokenfactory set-before-send-hook $DENOM $ALICE` pointing hook at an EOA (no contract)
4. Observe `distribution withdraw-all-rewards`, `staking delegate`, `staking unbond`, `staking redelegate` all fail with `failed to call before send hook ... no such contract`
5. For chain halt: have a delegator redelegate away from a validator that then gets slashed; BeginBlocker -> Slash -> SlashRedelegation -> Unbond -> BeforeDelegationSharesModified -> withdrawDelegationRewards errors, panicking ABCI
**How found:** Reading the tokenfactory MsgSetBeforeSendHook handler and tracing that the hook is invoked via Sudo on every bank send; noticed no validation that the hook address is a contract, then traced staking/distribution call paths (BeforeDelegationSharesModified -> withdrawDelegationRewards) that must transfer reward denoms, and the slashing BeginBlocker path that propagates errors to ABCI.
**Exploitation:** Attacker mints a tokenfactory denom, injects it into a validator's reward pool so delegators' pending rewards contain it, then sets the BeforeSendHook to a non-contract address. Any staking action requiring reward distribution now reverts, freezing bonded funds and rewards. If a redelegation exists from a validator that is subsequently slashed, the slashing path in BeginBlocker returns the hook error to ABCI, halting the chain.
**Escalation:** Escalated from frozen delegator funds to full chain halt by combining the broken hook with the automatic slashing of a redelegation during BeginBlocker.
**Insight:** When a module lets users register a callback invoked on every token transfer, check whether the callback target is validated as a live contract and whether any consensus-critical path (BeginBlocker, staking, slashing) performs that transfer and propagates the error — an unvalidated hook address becomes a chain-halt primitive.
