You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Potential security issue: SignTxMessage signature does not bind derivation_path #162
I found a potential security issue in Mpcium v0.3.5.
In pkg/types/initiator_msg.go, SignTxMessage.Raw() builds the canonical payload that is signed by the event initiator. The payload includes:
key_type
wallet_id
network_internal_code
tx_id
tx
However, it does not include:
derivation_path
This means the initiator signature authenticates the transaction digest and wallet id, but does not cryptographically bind the HD derivation path used for signing.
Impact:
If an attacker is able to modify or republish a signed SignTxMessage on the NATS/message bus, they may be able to change derivation_path without invalidating the
initiator signature. The MPC nodes could then sign the same transaction digest with a different derived child key than the one intended by the client/coordinator.
In many blockchain cases this may produce an invalid transaction signature, but it is still a security boundary issue: the field that selects the signing child key should be
covered by the authenticated message.
This may also affect authorizer signatures, because ComposeAuthorizerRaw() appears to sign the initiator raw payload/signature, and the initiator raw payload also excludes derivation_path.
Expected behavior:
derivation_path should be included in the canonical signed payload for SignTxMessage.Raw().
Suggested fix:
Include DerivationPath in the signed payload, for example:
If backwards compatibility is required, a versioned signing payload may be safer.
Affected version tested:
github.com/fystack/mpcium v0.3.5
I have not tested this against a production deployment. This report is based on source-code review of the message canonicalization and signature verification boundary.
Adds DerivationPath to the canonical payload in SignTxMessage.Raw(), so the field selecting the signing child key is authenticated by the initiator signature. ComposeAuthorizerRaw() wraps Raw(), so authorizer signatures now cover it too.
Uses json:"derivation_path,omitempty" for backward compatibility: messages with an empty derivation_path serialize byte-for-byte as before, so existing signed traffic keeps verifying (no lockstep upgrade needed for the empty-path case).
Includes unit tests for the signature-binding property (tampering derivation_path breaks verification) plus a VerifyInitiatorMessage test through the production verify path.
Activity
anhthii commentedon Jul 1, 2026
hi @TimurZur , thank you for reporting. Our team will check this and fix soon. thanks!
DNK90 commentedon Jul 3, 2026
Opened #163 with a fix for this.
DerivationPathto the canonical payload inSignTxMessage.Raw(), so the field selecting the signing child key is authenticated by the initiator signature.ComposeAuthorizerRaw()wrapsRaw(), so authorizer signatures now cover it too.json:"derivation_path,omitempty"for backward compatibility: messages with an emptyderivation_pathserialize byte-for-byte as before, so existing signed traffic keeps verifying (no lockstep upgrade needed for the empty-path case).derivation_pathbreaks verification) plus aVerifyInitiatorMessagetest through the production verify path.PR: #163
fix(types): bind derivation_path in SignTxMessage.Raw() (fystack#162)
Merge pull request #163 from DNK90/fix/issue-162-bind-derivation-path