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.

Attempted 3 times ([#8462], [#8539], [#8658]) and reverted each time.
Root cause of prior failures: coin-level verifyTssTransaction overrides had
stale hardcoded arrays missing staking types, so the guard threw for legitimate
staking transactions even when resolveEffectiveTxParams passed them through.

---
14-Day Dry-Run (2026-05-21 to 2026-06-03)

Two sources queried  Loki is authoritative (Prometheus undercounts due to
in-memory counter resets across pod restarts):

Loki  wallet-platform + wallet-platform-admin-nocluster  444 entries

┌────────┬────────────────┬───────────┬─────────────┬──────────────────┐
  Coin      tx_type      Loki hits  Kibana hits       Status      
├────────┼────────────────┼───────────┼─────────────┼──────────────────┤
 canton  enableToken     206        76           already exempt   
├────────┼────────────────┼───────────┼─────────────┼──────────────────┤
 sol     customTx        106        50           already exempt   
├────────┼────────────────┼───────────┼─────────────┼──────────────────┤
 canton  createAccount   89         34           added in this PR 
├────────┼────────────────┼───────────┼─────────────┼──────────────────┤
 sol     enableToken     22         10           already exempt   
├────────┼────────────────┼───────────┼─────────────┼──────────────────┤
 canton  transferAccept  8          7            added in this PR 
├────────┼────────────────┼───────────┼─────────────┼──────────────────┤
 bsc     tokenApproval   6          0*           already exempt   
├────────┼────────────────┼───────────┼─────────────┼──────────────────┤
 hash    contractCall    3          0*           added in this PR 
├────────┼────────────────┼───────────┼─────────────┼──────────────────┤
 ada     pledge          2          1            added in this PR 
├────────┼────────────────┼───────────┼─────────────┼──────────────────┤
 apt     customTx        2          0*           already exempt   
└────────┴────────────────┴───────────┴─────────────┴──────────────────┘

*Kibana index (logstash-beat-wallet-platform-prod*) does not cover the
wallet-platform-admin-nocluster app  those hits only appear in Loki.

hash/contractCall  3 Loki hits, all 3 are signing rounds for the same
txRequest (71cc470c), i.e. 1 unique transaction. Via
v2.admin.txrequest.signatureshare.bulk.create, user caseykampa@bitgo.com,
2026-06-02 19:30–19:33 UTC. hash (Provenance) uses secp256k1  ECDSA
enforcement would block this without the exemption.

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 payment, fanout, vote, defi-deposit, defi-redeem
in both Loki and Kibana across all 14 days. ECDSA enforcement is safe.

---
Changes

recipientUtils.ts (new)  single source of truth for the 27-type
NO_RECIPIENT_TX_TYPES set and resolveEffectiveTxParams(). Falls back to
intent.recipients, resolves txType from intent.intentType 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 (recipientUtils + ecdsaMPCv2 tests)
- 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
@mrdanish26 mrdanish26 force-pushed the wcn-151/security-issue branch from 8959f9d to 8c93794 Compare June 4, 2026 00:01
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