Skip to content

fix(sdk-core): enforce recipient verification in ECDSA TSS signing#8924

Draft
mrdanish26 wants to merge 1 commit into
masterfrom
wcn-151/security-issue
Draft

fix(sdk-core): enforce recipient verification in ECDSA TSS signing#8924
mrdanish26 wants to merge 1 commit into
masterfrom
wcn-151/security-issue

Conversation

@mrdanish26
Copy link
Copy Markdown
Contributor

@mrdanish26 mrdanish26 commented Jun 3, 2026

Ticket: WCN-151

Summary

Closes the default-path vulnerability in ECDSA TSS signing (WCN-151 Phase 3)
where a compromised BitGo API server could swap signableHex undetected.


The Vulnerability

Both EcdsaUtils and EcdsaMPCv2Utils defaulted txParams when absent:

// Before — vulnerable
txParams: params.txParams || { recipients: [] }

When txParams is not passed (Classic UI pending approval, Express),
verifyTransaction() receives an empty recipients list and skips all
address and amount verification. A compromised API server could swap
signableHex to redirect funds without the SDK detecting it.

This was attempted 3 times
(#8462,
#8539,
#8658)
and reverted each time. The core flaw in previous attempts: coin-level
verifyTssTransaction overrides had stale hardcoded arrays missing staking
types, so the guard threw missing txParams for legitimate staking
transactions even when resolveEffectiveTxParams correctly passed them through.

---
13-Day Dry-Run (2026-05-20 to 2026-06-02)

219 log entries / 95 unique txRequestIds from Grafana Loki (authoritative 
Prometheus undercounts 3.3× due to pod restarts across 9 deployments).

┌────────┬────────────────┬──────┬──────────────────┐
  Coin      tx_type      Hits       Status      
├────────┼────────────────┼──────┼──────────────────┤
 canton  enableToken     111   already exempt   
├────────┼────────────────┼──────┼──────────────────┤
 sol     customTx        70    already exempt   
├────────┼────────────────┼──────┼──────────────────┤
 canton  createAccount   32    added in this PR 
├────────┼────────────────┼──────┼──────────────────┤
 bsc     tokenApproval   12    already exempt   
├────────┼────────────────┼──────┼──────────────────┤
 canton  transferAccept  4     added in this PR 
├────────┼────────────────┼──────┼──────────────────┤
 ada     pledge          2     added in this PR 
└────────┴────────────────┴──────┴──────────────────┘

ada/pledge: stakingRequestId is not set on the Trust custodial path 
must be in the explicit set, cannot rely on the staking bypass.

Zero hits from value-transfer types (payment, fanout, contractCall,
vote) across all 13 days. ECDSA enforcement is safe.

---
Changes

recipientUtils.ts (new)  single source of truth for the 26-type
NO_RECIPIENT_TX_TYPES set and resolveEffectiveTxParams(). Falls back to
intent.recipients, resolves txType from intent when txParams.type is
absent, propagates stakingRequestId, and throws InvalidTransactionError
only when no recipients and no exemption applies.

ecdsa.ts + ecdsaMPCv2.ts  replace the vulnerable default:

// After — secure
txParams: resolveEffectiveTxParams(txRequest, params.txParams)

bsc.ts, bscToken.ts, xdc.ts, xdcToken.ts, evmCoin.ts,
abstractEthLikeNewCoins.ts  replace stale hardcoded arrays (4–7 types
each, all missing staking types) with NO_RECIPIENT_TX_TYPES.has(txParams.type)
plus stakingRequestId bypass.

iBaseCoin.ts, baseTypes.ts, iWallet.ts  add
stakingRequestId?: string to TransactionParams, PopulatedIntent, and
PrebuildTransactionResult.

---
Out of Scope

- EdDSA enforcement  Phase 4, separate PR
- bitgo-ui TssTxRecipientSource.Explicit call sites  Phase 3b

---
Test Plan

- yarn test --filter=@bitgo/sdk-core passes
- BSC delegate/undelegate  no missing txParams regression
- EVM tokenApproval, consolidate  no regression
- Canton createAccount, enableToken  no regression
- Normal ETH/BTC send with recipients  address + amount still verified
- Post-deploy Loki: |= "TSS signing with no intent recipients" 
zero new hits within 24h

@linear-code
Copy link
Copy Markdown

linear-code Bot commented Jun 3, 2026

WCN-151

@mrdanish26 mrdanish26 force-pushed the wcn-151/security-issue branch from 5feb507 to 8959f9d Compare June 3, 2026 03:06
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