AI-generated analysisPublished automatically and not human-verified. Validated context appears in community notes below.
← Watch feed
Low 34 Bitcoin

Compare cosigners before presuming multisig change

Public commit record

What the developer wrote

Authored by kdmukai

100/100 · Strong
Compare cosigners before presuming multisig change

A multisig output whose committed script holds this seed's key can
still belong to a different wallet: a 2-of-3 over {p1,p2,p4} when the
inputs spend {p1,p2,p3}. When the psbt supplies global xpubs and fully
annotates the output, _get_cosigners resolves a cosigner list for the
inputs and one for the output, and lists that differ mean the output
pays a quorum other than the one being spent from. That output is now
counted as an external spend. It stays presumed change when the lists
match or when either side's cosigners are unresolved.

This is hygiene, not a security control. The global xpubs are optional
and unauthenticated, so a coordinator that omits them skips the check,
and a mismatch demotes rather than raises because a transfer into a
second multisig this seed belongs to is legitimate. No surveyed
coordinator produces the shape the check fires on: every one except
Bitcoin Core annotates only its own wallet's outputs, and Core, which
annotates any output a descriptor in its wallet file can solve, writes
no global xpubs at all. Settling which wallet a multisig output pays
still needs the user's own descriptor.

The comparison sits after the ownership checks rather than at the
policy shape gate, so a psbt whose output cosigners fail to resolve
still faces every ownership check.

_get_cosigners' sorted() is what makes the two lists comparable: two of
the three multisig fixtures order the same wallet's keys differently on
the input and on its change output. Its docstring now separates what
is claim from what is checked and what the result does and does not
establish, its loop carries the procedure inline, and two early-outs
name the omitted-xpubs and omitted-derivations cases before the loop
(behaviour-neutral: both already raised from inside it). Tests pin the
sort, the different-quorum spend, and the no-xpubs presumed-change
fallback.
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
The short version

What changed, and why it matters

This commit tightens how SeedSigner decides whether a multisig payment back to the user is real 'change' or actually a payment to a different wallet. Before, if an output contained the user's key and looked like the same kind of multisig (for example, 2-of-3), the app assumed it was change. Now, when the PSBT file includes enough extra public-key data, the app compares the list of cosigners on the inputs versus the output. If the cosigner lists differ, the output is treated as an external spend instead of change. The commit itself calls this 'hygiene, not a security control' because the extra data is optional and unauthenticated, so a malicious or uncooperative coordinator can still bypass the check by omitting it.

Recommended action

Review the updated change-detection logic in the context of the device's UI to confirm users are clearly shown when an output is classified as a spend rather than change. Continue to treat global xpubs as untrusted coordinator data and ensure documentation warns users that descriptor-based verification remains necessary for multisig change validation.

Security signals we found

01

Multisig change-output presumption logic changed to compare input vs output cosigner lists

02

Optional/unauthenticated PSBT global xpubs used only as a hygiene check, not a hard security control

03

Mismatch demotes output from change to spend rather than raising an error

04

Function docstring explicitly states global xpubs and derivations are unproven coordinator claims

05

Tests cover sorted cosigner comparison, different-quorum spend detection, and fallback when xpubs are omitted

Risk score

Why this scored 34/100

Our methodology →
Potential impact 8/30
Exploitability 4/25
Stealth signal 6/15
Affected reach 5/15
Confidence 7/10
Evidence quality 4/5
Human-validated context

Community notes

Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.

No validated notes yet.

The AI analysis stands alone for now. Submit a note if you can add evidence or important context.