# Some proposals can be queued when governanceexecutor is paused

Venus OmnichainGovernanceExecutor's retryMessage path lacks whenNotPaused, letting failed LayerZero proposals be queued while the contract is paused.

- Payout: Contest reward
- Severity: medium
- Program: Venus
- Credited: zigtur
- Disclosed: 2024-04-25
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_venus_apr2024.pdf#3.1.1
- Library page: https://bugbountylibrary.com/r/cantina%3Avenus_apr2024%3A3.1.1
- Tags: domain:web3 impact:integrity kind:contest platform:cantina sev:medium tech:solidity technique:incomplete-fix technique:source-review vuln:access-control vuln:business-logic vuln:governance

**Target:** OmnichainGovernanceExecutor LayerZero message handler
**Root cause:** whenNotPaused is on _blockingLzReceive but not on _nonblockingLzReceive, so retryMessage bypasses the pause check and queues proposals.
**Steps:**
1. Owner pauses OmnichainGovernanceExecutor via pause().
2. A LayerZero proposal message arrives; _blockingLzReceive reverts on whenNotPaused, storing failedMessages[srcChainId][srcAddress][nonce] = keccak256(payload).
3. Call `retryMessage(srcChainId, srcAddress, nonce, payload)` with matching payload.
4. retryMessage clears failedMessages and calls _nonblockingLzReceive, which has no pause check.
5. Proposal is decoded, stored in proposals[pId], and _queue(pId) executes despite pause.
**How found:** Code reading of the pause modifier placement: noticed whenNotPaused only guards _blockingLzReceive, then traced retryMessage into _nonblockingLzReceive which lacks the check.
**Exploitation:** Attacker relies on a proposal message that failed during pause being stored as a failed message, then calls retryMessage to force queueing of the proposal while governance is paused.
**Insight:** When a pause guard sits on an entry wrapper, trace every alternate path into the inner handler (retry/replay functions) — inherited NonblockingLzApp retryMessage is a classic bypass of wrapper-level modifiers.
