MorphL2 — disclosed vulnerability reports and payouts
Every publicly disclosed and closed bug bounty report we hold for MorphL2, with our own summary of each finding and a link to the original disclosure.
- Reports indexed
- 9
- Total paid
- $0
- Critical
- 0
- Largest payout
- $0
This page collects the 9 closed, publicly disclosed MorphL2 reports indexed on CoinBuggie. Nothing here is active or unpatched — every entry was published by the programme or the researcher after remediation.
The findings concentrate in Logic error, Oracle manipulation, across EVM-Solidity. Reading a single protocol end to end is the fastest way to see which assumptions its codebase repeatedly gets wrong, which is usually a better predictor of where the next finding lives than the category alone.
Use the vulnerability class links below to compare these findings against the same bug class in other protocols.
What reviewers look for
- Logic error findings disclosed against MorphL2
- Oracle manipulation findings disclosed against MorphL2
Curated highlights
The largest disclosed payouts in this group, with our own summary of each. Every report links back to the original disclosure.
MorphL2: Delegators can lose their rewards when a delegator has removed a delegatee and claims all of his rewards before delegating again to a previous removed delegatee.
MorphL2's Distribute reward contract contains two interacting faults that let a delegator lose earned staking rewards permanently, even when following the intended flow. The first is in claimAll, which iterates over the delegatees EnumerableSet while _claim removes undelegated delegatees from that same set; because the set shrinks mid-loop, the loop index catches up to the new length and exits before visiting every delegatee, leaving some rewards unclaimed and unacknowledged. The second is in notifyDelegation, which on a fresh delegation to a previously undelegated delegatee unconditionally resets unclaimedStart to the effective epoch without first settling any pending rewards, and since _claim only pays out epochs at or after unclaimedStart, those pending rewards become forfeited. Together a user who undelegates, claims all rewards, then re-delegates to a previously removed delegatee loses whatever rewards the first bug skipped, locking the tokens in the Distribute contract. The protocol team fixed the issue in morph-l2/morph PR #594.
MorphL2: In the `revertBatch` function, `inChallenge` is set to `false` incorrectly, causing challenges to continue after the protocol is paused.
MorphL2's L1 Rollup contract mishandles the global challenge flag inside revertBatch: it clears inChallenge for any reverted batch whose challenges[_batchIndex].finished evaluates false, which also holds for batches that were never challenged at all. As a result, when the owner reverts an unchallenged trailing batch while a separate earlier batch is mid-challenge, the ongoing challenge's flag is silently reset to false. If the protocol is then paused for longer than the challenge/proof window, the prover cannot submit a proof in time even for a valid batch and gets slashed, while the challenger collects reward plus slash penalty despite no real batch fault. The maintainers fixed it by gating the flag reset behind a batchInChallenge check in the merged PR #561, and the report's medium severity matched Sherlock's adjudicated outcome for this finding.
MorphL2: Malicious sequencer can DoS proposal execution by inflating the amount of proposals to be pruned
Morph's L2 governance contract Gov.sol prunes all proposals between undeletedProposalStart and the ID being executed when any proposal is executed. Since createProposal() has no creation limits and is restricted only to sequencers, a malicious sequencer can inflate currentProposalID by creating thousands of low-value proposals. Any subsequent legitimate proposal execution then walks an unbounded pruning loop that can exceed the block gas limit, reverting with an out-of-gas error and freezing governance parameter updates permanently. The fix introduced a cooldown between proposal creations so the owner can remove a misbehaving sequencer in L1 before the L2 denial-of-service becomes unrecoverable.
MorphL2: The 255th staker in `L1Staking.sol` can avoid getting slashed and inadvertently cause fund loss to stakers
MorphL2's L1Staking.sol supports up to 255 active stakers, but the getStakersFromBitmap helper iterates its bit loop only up to i < 255, skipping the bit that represents the 255th staker. When a challenged batch is committed by that staker, slash() expands the saved sequencers bitmap to an array containing address(0) rather than the real staker, so the removal and whitelist-deletion mutations target the zero address. The misbehaving staker consequently stays active and can keep committing invalid batches while the protocol continues to pay the challenger reward out of the shared staking pool, eventually depleting its ETH and breaking withdrawals and future slashings. A one-line loop-bound change closes the gap and was merged in the protocol's fix PR.
MorphL2: Sequencer will be underpaid because of incorrect `commitScalar`
MorphL2's GasPriceOracle computes the L1 data fee for users via `commitScalar * l1BaseFee + blobScalar * data.length * l1BlobBaseFee`, but the configured `commitScalar` (230e9) is underpriced 100X versus the true cost (should be 230_000e9). Because the scalar covers the gas of executing `commitBatch()` on L1, users pay dramatically less than the sequencer actually spends to post a batch. An attacker can repeatedly submit 128kb-calldata zero-value transfers that cost ~$0.13 in L2 fees but force the sequencer to spend ~$15.98 in L1 gas, permanently draining sequencer revenue and making the chain uneconomical. The flaw exists even without malicious users, as the chain slowly bleeds revenue on normal traffic, and the erroneous value appears to have been copied from Scroll's implementation where it was also validated as a bug.
MorphL2: Attacker can freeze chain and steal challenge deposits using fake `prevStateRoot`
Morph L2's Rollup.sol only validates that a committed batch's prevStateRoot matches the previous batch's postStateRoot inside finalizeBatch(), not at commit time. A malicious sequencer can therefore commit a batch that performs a valid state transition rooted at a fabricated prevStateRoot. Since the transition is valid, the sequencer can provide a genuine proof and win any challenge, stealing the honest challenger's deposit while avoiding the slashing penalty, even though the batch can never be finalized. Because batches finalize sequentially, this freezes the entire chain until manual admin rollback. The fix adds a prevStateRoot equality check in commitBatch(), confirmed in morph-l2/morph PR 616.