Skip to content

fix(derivation): guard against blockCount underflow on malformed batches#953

Merged
curryxbo merged 1 commit into
feat/multi_batchfrom
fix/derivation-blockcount-underflow
May 18, 2026
Merged

fix(derivation): guard against blockCount underflow on malformed batches#953
curryxbo merged 1 commit into
feat/multi_batchfrom
fix/derivation-blockcount-underflow

Conversation

@curryxbo
Copy link
Copy Markdown
Contributor

@curryxbo curryxbo commented May 18, 2026

Summary

Re-apply the underflow guard in BatchInfo.ParseBatch (originally landed as commit aae2213 on this branch and reverted by 82e7062 without replacement). Addresses audit feedback on PR #935.

The bug

In node/derivation/batch_info.go::ParseBatch, both block-count derivation paths subtract two attacker-controllable uint64 values without bounds checking:

// V0 -> V1+ transition
blockCount = batch.LastBlockNumber - startBlock.Number + 1

// V1+
blockCount = batch.LastBlockNumber - parentBatchBlock

batch.LastBlockNumber is read directly from L1 calldata; the L1 Rollup contract does not constrain its relationship to the parent batch. A malformed batch with LastBlockNumber < parentBatchBlock (or LastBlockNumber < startBlock.Number in the V0→V1 path) underflows blockCount to a near-2^64 value.

Downstream, bcLen := blockCount * 60 wraps modulo 2^64. For specific attacker-chosen LastBlockNumber values, bcLen wraps to a small number, the boundary check if uint64(len(batchBytes)) < bcLen passes spuriously, and the subsequent loop (for i := 0; i < int(blockCount); i++) iterates against rawBlockContexts[i*60 : i*60+60] and panics with a slice-out-of-range. Net effect: a single malformed L1 commit batch crashes every honest derivation node simultaneously.

The fix

Reject the malformed batch with a clear error before the subtraction, in both paths:

  • V0 → V1+ transition: error if batch.LastBlockNumber < startBlock.Number
  • V1+: error if batch.LastBlockNumber < parentBatchBlock

Asymmetry between the two guards is intentional — V0→V1 has a + 1 so equality represents a valid 1-block batch; V1+ does not, so equality represents an empty (0-block) batch which does not panic and is therefore out of scope for this PR.

10 lines, no behavioral change on well-formed batches.

Why this is being re-applied

Commit aae2213 originally landed this fix on feat/multi_batch on 2026-05-11. Commit 82e7062 reverted it ~1h later with a one-line message and no replacement implementation; the underflow path has been live on the branch ever since. Audit review on PR #935 flagged the same panic vector independently, so the fix is going back in.

Test plan

  • Local go build ./... in node/
  • CI passes
  • Manual: construct a fake RPCRollupBatch with LastBlockNumber < parent.LastBlockNumber() in unit context and confirm ParseBatch returns the new error rather than panicking. (Regression test deliberately not bundled in this PR — kept scope minimal at the request of the reviewer; tracked separately.)

🤖 Generated with Claude Code

@curryxbo curryxbo requested a review from a team as a code owner May 18, 2026 02:33
@curryxbo curryxbo requested review from SecurityLife and removed request for a team May 18, 2026 02:33
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 84cf70cb-7d1d-4e18-becb-e3ab4f888f5b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/derivation-blockcount-underflow

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

batch.LastBlockNumber and the reference block (decoded startBlock for the
V0->V1+ transition or parent header's LastBlockNumber for V1+) are not
constrained by the L1 Rollup contract, so a malformed batch with
LastBlockNumber below the reference would underflow blockCount and lead
to a makeslice panic downstream in the blob-only path. Reject such
batches with a clear error before subtracting.

Co-authored-by: Cursor <cursoragent@cursor.com>
@curryxbo curryxbo force-pushed the fix/derivation-blockcount-underflow branch from 49cfa0a to aee8855 Compare May 18, 2026 02:49
@curryxbo curryxbo merged commit 84ae08d into feat/multi_batch May 18, 2026
7 checks passed
@curryxbo curryxbo deleted the fix/derivation-blockcount-underflow branch May 18, 2026 02:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant