Skip to content

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

Open
leolambo wants to merge 1 commit into
bitpay:masterfrom
leolambo:fix/verifier-prepublishraw-binding
Open

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

Conversation

@leolambo

@leolambo leolambo commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Description

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)

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.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@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
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