Skip to content

fix(abstract-eth): verify inner batch calldata recipients [CGD-1319]#8771

Closed
kamleshmugdiya wants to merge 1 commit into
masterfrom
claude/objective-mahavira-0da6eb
Closed

fix(abstract-eth): verify inner batch calldata recipients [CGD-1319]#8771
kamleshmugdiya wants to merge 1 commit into
masterfrom
claude/objective-mahavira-0da6eb

Conversation

@kamleshmugdiya
Copy link
Copy Markdown
Contributor

Description

verifyTransaction for ETH batcher-contract sends only checked (a) the sum of txParams.recipients against txPrebuild.recipients[0].amount and (b) that the outer recipient was the network's batcherContractAddress. It never decoded the inner batch(address[],uint256[]) calldata embedded in txPrebuild.txHex, and signTransaction then loaded that txHex verbatim.

A compromised BitGo platform could preserve both outer checks while swapping the inner (address, amount) pairs to attacker-controlled addresses, redirecting batched payouts. This PR decodes the inner calldata during verification and compares each pair to user intent.

Issue Number

CGD-1319

Type of change

  • Bug fix (non-breaking change which fixes an issue)

What changed

  • modules/abstract-eth/src/lib/walletUtil.ts — exports batchMethodId (0xc00c4e9e), batchMethodName, batchMethodTypes.
  • modules/abstract-eth/src/lib/iface.ts — adds BatchTransferData / BatchTransferRecipient.
  • modules/abstract-eth/src/lib/utils.ts — adds decodeBatchTransferData(), modeled after the existing decode*TransferData helpers and reusing getRawDecoded / getBufferedByteCode.
  • modules/abstract-eth/src/abstractEthLikeNewCoins.ts — adds private verifyBatchInnerRecipients which parses txPrebuild.txHex, decodes the outer sendMultiSig, decodes the inner batch(address[],uint256[]), and compares each (address, amount) pair to txParams.recipients. Wired into the existing batch path in verifyTransaction for native batches.

The verifier fails closed when:

  • txPrebuild.txHex is missing
  • the outer selector is not sendMultiSig
  • the inner selector is not batch(address[],uint256[])
  • inner recipient count, address, or amount differ from txParams.recipients

Token-batch (txParams.tokenName) and TSS paths are out of scope per the issue; the codebase has no sendMultisigBatch-style token wrapper, and the existing token branch already expects txPrebuild.recipients[0].amount === 0. signTransaction is unchanged — it now safely loads txHex because the verifier proves inner calldata matches user intent first.

ENS / non-hex txParams addresses skip the address comparison but still enforce the amount check, mirroring the normal-tx path at abstractEthLikeNewCoins.ts:3340.

How Has This Been Tested?

  • modules/abstract-eth/test/unit/utils.ts — 4 tests for decodeBatchTransferData: hardcoded selector matches runtime-computed value, round-trip encode/decode, wrong-selector rejection, mismatched-array-length rejection.
  • modules/sdk-coin-eth/test/unit/eth.ts — adds a buildBatchTxHex helper and 5 new verifyTransaction tests: missing txHex, tampered inner address, tampered inner amount (with outer total preserved), wrong inner selector, mismatched inner recipient count. Updates the existing happy-path batch test to include a valid txHex.

Local runs:

  • yarn unit-test in modules/abstract-eth77 passing
  • yarn unit-test in modules/sdk-coin-eth237 passing
  • yarn lint in both modules — clean

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My code compiles correctly for both Node and Browser environments
  • I have commented my code, particularly in hard-to-understand areas
  • My commits follow Conventional Commits and I have properly described any BREAKING CHANGES
  • The ticket or github issue was included in the commit message as a reference
  • I have made corresponding changes to the documentation and on any new/updated functions and/or methods - jsdoc
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Decode the inner batch(address[],uint256[]) calldata embedded in
txPrebuild.txHex and compare each (address, amount) pair to the
user-supplied recipients. Without this check, the verifier validated
only the outer batcher contract address and the total amount, so a
compromised platform could swap inner recipients while preserving the
outer wrapper checks and redirect batched payouts.

Fails closed when txHex is missing, the outer selector is not
sendMultiSig, or the inner selector is not batch(address[],uint256[]).

Ticket: CGD-1319
@kamleshmugdiya kamleshmugdiya requested a review from a team as a code owner May 14, 2026 07:40
@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 14, 2026

CGD-1319

@kamleshmugdiya kamleshmugdiya deleted the claude/objective-mahavira-0da6eb branch May 14, 2026 07:42
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