Skip to content

[BWS][BWC][CWC] Bind prePublishRaw fallback to the proposal - #4232

Open
leolambo wants to merge 2 commits into
bitpay:masterfrom
leolambo:fix/verifier-prepublishraw-binding
Open

[BWS][BWC][CWC] Bind prePublishRaw fallback to the proposal#4232
leolambo wants to merge 2 commits into
bitpay:masterfrom
leolambo:fix/verifier-prepublishraw-binding

Conversation

@leolambo

@leolambo leolambo commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Description

IS-1422 · Bug Bounty 2643811

The transaction verifier falls back to txp.prePublishRaw when it can't match the creator's signature against the locally rebuilt tx. It only checked that the signature was valid over prePublishRaw, not that prePublishRaw was the same proposal, so a compromised wallet service could keep a valid signature, swap the destination, and still pass the check. The fallback now recovers the one field the server changes at publish (the Solana blockhash or the EVM/XRP nonce) from prePublishRaw, puts it back on the current proposal, and requires a byte-for-byte match, so any other change fails as SERVER_COMPROMISED.

Changelog

  • Recover the server-mutated field from prePublishRaw and require the rebuilt proposal to match it exactly, so a tampered destination or amount fails as SERVER_COMPROMISED.
  • Reject prePublishRaw on UTXO chains, which never mutate a field at publish.
  • Guard the server-side publishTx fallback the same way, so a tampered stored proposal can't reuse an old signature.
  • Add getMutableFields to the SOL, EVM, and XRP providers to pull that field back out of a raw tx.

Testing Notes

New tests at each layer:

  • crypto-wallet-core: getMutableFields recovery for SOL, EVM, and XRP
  • bitcore-wallet-client: checkPrePublishRaw accepts a refreshed field and rejects a tampered destination
  • bitcore-wallet-service: isPrePublishRawBound plus an end-to-end publishTx that rejects a tampered stored proposal

Run npm test in each of those three packages.


Checklist

  • I have read CONTRIBUTING.md and verified that this PR follows the guidelines and requirements outlined in it.
  • I have added the appropriate package tag(s) (e.g. BWC if modifying the bitcore-wallet-client package, CLI if modifying the bitcore-cli package, etc.)
  • I have verified that this is not an existing PR (open or closed)

@leolambo leolambo changed the title Bind prePublishRaw fallback to the proposal [BWS][BWC][CWC] Bind prePublishRaw fallback to the proposal Aug 28, 2026
@leolambo
leolambo marked this pull request as ready for review August 28, 2026 19:23
Verifier.checkTxProposalSignature falls back to txp.prePublishRaw when
the locally-rebuilt tx does not match the creator's signature. It only
checked that the signature was valid over prePublishRaw, never that
prePublishRaw described the proposal being verified. A compromised
server could pair a valid (prePublishRaw, proposalSignature) with a
tampered destination and the check still passed.

Bind prePublishRaw to the proposal. Recover the single field the server
mutates at publish -- the Solana recent blockhash or the EVM/XRP nonce
-- from prePublishRaw, rebuild the current proposal with that value
substituted, and require a byte-for-byte match. Any other difference
(destination, amount, from, contract) now fails as SERVER_COMPROMISED.
Non-mutable chains (UTXO) reject prePublishRaw outright.

The same guard is applied to the server-side publishTx fallback.
@leolambo
leolambo force-pushed the fix/verifier-prepublishraw-binding branch from 16fc803 to 4386a26 Compare August 31, 2026 12:36
@kajoseph
kajoseph requested a lite review from Copilot September 3, 2026 14:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The changes are security-critical and span core tx parsing plus client/server signature verification paths, so a final human review is recommended before approval.

Pull request overview

This PR hardens the prePublishRaw signature fallback path by cryptographically binding prePublishRaw to the current proposal for chains where BWS mutates a publish-time field (SOL blockhash, EVM/XRP nonce), preventing a compromised server from replaying a valid signature while swapping destination/amount.

Changes:

  • Adds getMutableFields(rawTx) to SOL/EVM/XRP transaction providers to recover the publish-mutable field from a raw tx.
  • Updates BWC verifier and BWS publish flow to only accept prePublishRaw fallback when the rebuilt proposal matches prePublishRaw byte-for-byte after restoring the mutable field.
  • Adds unit/integration tests across CWC/BWC/BWS, and rejects prePublishRaw on UTXO chains.
File summaries
File Description
packages/crypto-wallet-core/test/transactions.test.ts Adds coverage for getMutableFields recovery on SOL/EVM/XRP.
packages/crypto-wallet-core/src/transactions/xrp/index.ts Implements getMutableFields for XRP (Sequence/nonce).
packages/crypto-wallet-core/src/transactions/sol/index.ts Implements getMutableFields for SOL (recent blockhash from compiled message).
packages/crypto-wallet-core/src/transactions/eth/index.ts Implements getMutableFields for EVM (nonce).
packages/bitcore-wallet-service/test/integration/server.test.ts Adds BWS integration tests for binding checks and publish fallback tamper rejection.
packages/bitcore-wallet-service/src/types/chain.d.ts Extends IChain interface with isPrePublishRawBound.
packages/bitcore-wallet-service/src/lib/server.ts Guards publish-time signature fallback to prePublishRaw with binding check.
packages/bitcore-wallet-service/src/lib/common/utils.ts Adds shared isPrePublishRawBound implementation for account-based chains.
packages/bitcore-wallet-service/src/lib/chain/xrp/index.ts Wires chain-level isPrePublishRawBound for XRP.
packages/bitcore-wallet-service/src/lib/chain/sol/index.ts Wires chain-level isPrePublishRawBound for SOL.
packages/bitcore-wallet-service/src/lib/chain/index.ts Exposes ChainService.isPrePublishRawBound via proxy.
packages/bitcore-wallet-service/src/lib/chain/eth/index.ts Wires chain-level isPrePublishRawBound for EVM chains.
packages/bitcore-wallet-service/src/lib/chain/btc/index.ts Explicitly rejects prePublishRaw binding on UTXO chains.
packages/bitcore-wallet-client/test/verifier.test.ts Adds BWC tests for refreshed mutable field acceptance and tampering rejection.
packages/bitcore-wallet-client/src/lib/verifier.ts Adds checkPrePublishRaw binding guard and tightens fallback signature verification.
Review details
  • Files reviewed: 14/15 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/bitcore-wallet-client/src/lib/verifier.ts
Comment thread packages/bitcore-wallet-service/src/lib/common/utils.ts
The binding check's catch dumped the full error object with %o, which
adds noise to production logs. Log the stack or message string instead,
matching the pattern used elsewhere in this file.
@@ -305,6 +316,51 @@ export class Verifier {
return true;

@MichaelAJay MichaelAJay Sep 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the problem is larger than playing whack-a-mole with known false cases. Consider how to make this return true only for explicit trust situations, instead of for all situations we can't explicitly think of.

}).should.be.true;
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we need XRP?

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.

3 participants