# Consensus validator accepts blocks with mismatched basefee and execution `basefeepergas`

Monad consensus validator never checks consensus base_fee against execution base_fee_per_gas, letting a malicious proposer finalize a block execution rejects, splitting consensus and execution.

- Payout: Contest reward
- Severity: medium
- Program: Monad
- Credited: lian886
- Disclosed: 2026-02-26
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2025-09-monad#m-07
- Library page: https://bugbountylibrary.com/r/c4%3A2025-09-monad%3AM-07
- Tags: domain:web3 impact:dos impact:integrity kind:contest platform:code4rena sev:medium tech:rust technique:source-review vuln:business-logic vuln:misconfiguration

**Target:** Consensus block validator (Rust) / execution header validation
**Root cause:** validate_block_header re-validates ancillary ProposedEthHeader fields but never enforces equality between the consensus header's base_fee and the execution header's base_fee_per_gas; fee checks fall back to header.base_fee.unwrap_or(PRE_TFM_BASE_FEE).
**Steps:**
1. Proposer builds execution header with high base_fee_per_gas via EthTxPool::create_proposal (pool/mod.rs:357).
2. Independently set consensus header base_fee low (or None pre-TFM) via txpool.rs:320 -> consensus.rs:360.
3. Submit block; validate_block_header accepts since it never compares the two base fees.
4. validate_block_body fee checks use header.base_fee.unwrap_or(PRE_TFM_BASE_FEE), passing with the low value.
5. Consensus finalizes; execution's static_validate_consensus_header raises BaseFeeMismatch (validatemonadblock.cpp:40), halting executors.
**How found:** Code review of validate_block_header noting it only re-validates ancillary ProposedEthHeader fields; traced the two independent data paths building execution vs consensus headers and the late execution-side BaseFeeMismatch check.
**Exploitation:** Malicious proposer deliberately diverges consensus base_fee from execution base_fee_per_gas so the block passes Rust-side validation and is voted in by consensus, but execution rejects it with BaseFeeMismatch; max-fee transactions between the forged and true base fee fail to cover gas, guaranteeing execution failure and a persistent consensus/exec split across all replicas.
**Escalation:** Every replica receives the same finalized header and hits identical BaseFeeMismatch, halting executors network-wide and leaving the ledger stuck until operator intervention.
**Insight:** When a system builds the same logical value (base fee) through two independent code paths, check whether the validator compares them; a fallback like unwrap_or(constant) can mask divergence until a downstream component rejects it, turning a validation gap into a consensus/exec split.
