Full Report
In Scroll zkEVM rollups, transactions occur in two main steps: EVM executes all transactions, performs state transitions and then sends the transaction to the provers. zkEVM prover proves the traces. This second step is known for being time consuming. So, due to this, there is a limited capacity. Scroll imposes a row consumption limit of transactions per block, rejects and reogs before finalizing if this happens. If transaction traces exceed the row capacity, the zk prover will fail. Obviously, an unprovable block prevents the chain from finalizing and wastes resources. Scroll knew this and implemented the Circuit Capacity Checker (CCC) in l2-geth to validate transactions before they enter the zkEVM circuit. Wow! We're looking at remediations within remediations for bugs, crazy! The mining process is as follows: Transaction enter the mempool, where it's picked up by a worker. Transactions are processed based upon gas price. Each transaction is executed one by one. Commit the block. If the CCC calculations failed, then rollback the block. The CCC functions as a post-sealing check rather than a pre-sealing check. This enables an attacker to send a lot of malicious transactions that exceed the CCC limit but are totally valid otherwise. This means that a lot of computations are done (wasting time and resources) only for a reorg to happen. The cool part is that since there's a reorg, there's no gas cost to the attacker! So, they can create an infinite amount of high gas price transactions to always be at the front of the queue to permanently stale the blockchain. Technically, it's interesting how they abused the issue. Now... for the drama. The vulnerability was reported to Scroll who decided not to fix the issue. They had received multiple similar types of vulnerabilities in CCC and understood there were likely more. So, they had completely redesigned the feature but were just waiting until the next release to upgrade it. Scroll and Immunefi agreed the vulnerability was legit. For the time being, Scroll was okay accepting this risk for the users and moving on, though. Because nothing was changed, no bug payout. The author of the report published the report on Twitter and a blog-like website, including full Immunefi chat logs. Some folks believe that the whitehat is in the right, while others think they are in the wrong. It's a sticky situation. From the perspective of the bug hunter, I get it - there's a live vuln and a program you did research on. From the perspective of the project, I get it - you recognized a design weakness and already fixed it. In my opinion, there's nothing on the Scroll side to do besides push their new code. So, if they're okay with the risk they're taking on with a DoS until the upgrade, that's their decision to make. When pushing for remediation on a bug bounty report, we got to be patient on things. Reading the communications, the bug hunter was pushing for comms faster than the SLA of Immunefi required and was very aggressive about it. Additionally, after being offered a bounty of 1K they pushed back and asked for a bounty of 200-300K. They even pushed up the severity of the bug citing the primacy of impact by creating some reasons on why the DoS was so bad. Personally, I feel like the denial of service risk commonly referred to on projects gets more credit than it should. Realistically, if this attack was launched, the chain would be back up in less than a day with a hacky-solution for this issue. The numbers and impact the author cites for Token Sell-Off & Investor Confidence Crisis are a little ridiculous to me. Sure, a DoS on the chain has impact but not 200K bug bounty worth of impact. Besides my grieves with how it was handled, the blog post is very thorough and well-explained.
Analysis Summary
# Vulnerability: Scroll zkEVM Denial of Service via Circuit Capacity Checker (CCC) Bypass
## CVE Details
- **CVE ID**: N/A (Project opted for a redesign rather than assigning a CVE to the specific flaw)
- **CVSS Score**: Estimated 7.5 (High) - *Based on Availability impact*
- **CWE**: CWE-400: Uncontrolled Resource Consumption; CWE-691: Insufficient Control Flow Management
## Affected Systems
- **Products**: Scroll zkEVM L2 Rollup (`l2-geth`)
- **Versions**: Versions prior to the "Curie" upgrade/CCC redesign
- **Configurations**: Default mining/sequencing configuration using the original Circuit Capacity Checker (CCC) implementation.
## Vulnerability Description
The flaw resides in the design of the **Circuit Capacity Checker (CCC)**, a mechanism intended to ensure transactions do not exceed the row capacity of Scroll’s zkEVM provers.
The CCC was implemented as a **post-sealing check** rather than a pre-sealing check. In the mining flow, transactions enter the mempool and are processed by a worker based on gas price. The worker executes and commits the block first; only then does the CCC validate if the block's traces fit within prover limits. If the CCC calculation fails, the block is rolled back (reorged).
Because the rollback occurs after significant computation but before the transaction is permanently recorded on the ledger, an attacker can submit transactions that intentionally exceed CCC limits. This triggers a computational loop where the sequencer wastes resources processing "invalid-for-circuit" transactions that are never finalized, leading to a permanent stall of the blockchain.
## Exploitation
- **Status**: PoC available (Published by researcher via Twitter/Blog)
- **Complexity**: Low
- **Attack Vector**: Network (Public Mempool)
- **Financial Cost**: Near Zero. Since the block reorgs when the CCC fails, the attacker’s transactions are never "finalized," meaning gas fees are never deducted from the attacker's balance.
## Impact
- **Confidentiality**: None
- **Integrity**: Low (Causes temporary chain instability and reorgs)
- **Availability**: **High** (The chain can be permanently stalled as long as the attacker continues sending high-gas-price malicious transactions).
## Remediation
### Patches
- **Redesign Update**: Scroll initiated a complete redesign of the CCC feature to move capacity checks earlier in the transaction lifecycle (pre-sealing). Users should ensure they are running the latest version of `l2-geth` post-Curie upgrade.
### Workarounds
- **Hacky-fix**: Emergency implementation of manual filters or stricter mempool validation rules to drop transactions that exhibit trace-heavy patterns.
- **Resource Management**: Increasing sequencer hardware capacity (though this does not solve the underlying logic flaw).
## Detection
- **Indicators of Compromise**: Frequent L2 reorgs occurring despite transactions appearing valid; high CPU utilization on sequencer nodes with zero progress in block finalization.
- **Detection Methods**: Monitoring logs for `CCC calculation failed` or `rollback` events in the `l2-geth` execution client.
## References
- **Researcher Blog**: hxxps[://]mirror[.]xyz/ (Details mentioned in report regarding Twitter/Blog publication)
- **Project Site**: hxxps[://]scroll[.]io/
- **Platform**: hxxps[://]immunefi[.]com/