Repository navigation
Releases
Unified opt-in sighash: 5.6.3U (Mk4/Mk5), 1.5.3QU (Q)
COLDCARD firmware adding the unified opt-in signature hash from Bitcoin Knots, on top of Coinkite's 5.6.3 / 1.5.3Q. Built from release/v5.6.3U at 358e150e.
A Bitcoin hardfork adds one signature message shared by every script type, opted into per input by hash type bit 0x20; Bitcoin Knots v29.4.2.knots20260508 specifies it in doc/unified-sighash.md. This carries no activation height and decides no consensus rules: the wallet that builds the PSBT decides which message to ask for.
Not affiliated with Coinkite. Coinkite has not adopted the fork, so use their firmware instead if that is what you want.
What it does
A PSBT may request hash types 0x21, 0x22, 0x23, 0xa1, 0xa2, 0xa3. A signature made with one commits to every spent amount and scriptPubKey rather than only the input being signed, which closes CVE-2020-14199 and CVE-2013-2292 for those inputs, and does not verify under the pre-fork rules, so the transaction cannot be replayed onto a chain without the rule.
Signing is byte-for-byte unchanged unless a PSBT asks for it.
The approval screen says what the signature covers. ANYONECANPAY has its own wording, because those commit to that input's own amount and to no other. 0x20 and 0xa0 are refused: they set the bit but name no output type.
Covers bare, P2SH and segwit v0. This tree does not sign taproot, so the rule's taproot script types are unreachable here.
Changes from 5.6.2U / 1.5.2QU
Rebased onto Coinkite's 5.6.3, so it carries their 40 newer commits including hardened PSBTv2 parsing, Codex32 and Shamir Secret Sharing, and a warning before risky firmware upgrades. The firmware change itself is unchanged.
One commit fewer: the multisig test-fixture fix this fork carried is now upstream.
Not signed by Coinkite
Signed with key zero, the development key published in the firmware repo, so it proves nothing about who built it. Permanently: a warning screen and forced delay on every boot, no green "genuine" light, and the main PIN is still required to install. A crash before the login sequence completes is not recoverable. Do not put this on a device holding funds you cannot afford to lose access to.
Files
| file | model | version |
|---|---|---|
2026-10-02T1600-v5.6.3U-mk-coldcard.dfu |
Mk4 / Mk5 | 5.6.3U |
2026-10-02T1600-v1.5.3QU-q1-coldcard.dfu |
Q | 1.5.3QU |
SHA256SUMS / SHA256SUMS.asc |
checksums and detached signature |
d8e3e720959007e7b8d07517e99780e3bb90c8af0b1f54f1d4a23d768c7374aa 2026-10-02T1600-v1.5.3QU-q1-coldcard.dfu
0671e9d26aa4c69f4704f90d930b6bef0e53ddeffd8c1d2e8d9532e19456b279 2026-10-02T1600-v5.6.3U-mk-coldcard.dfu
gpg --recv-keys A47D99B6DB0D715D40C59A2023AE8A8EA7E24E38
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum -c SHA256SUMSReproducing the build
Both images rebuild bit-for-bit from source. Verified with the repo's own checker, not a hand-rolled hash:
git clone https://github.com/privkeyio/cc-firmware && cd cc-firmware
git checkout d229e5e4 && git submodule update --init
cp ~/Downloads/2026-10-02T1600-v5.6.3U-mk-coldcard.dfu releases/
cd stm32 && make -f MK-Makefile repro # Q1-Makefile for the QIt ends in You have built a bit-for-bit identical copy of Coldcard firmware. check-repro splits the published DFU and diffs a full hexdump against the rebuild, excluding only the 128-byte header at 0x3f80. That header holds the build timestamp and the signature over it, which is why the DFU's own hash never matches a rebuild while the firmware body does.
Reproduce from d229e5e4, one commit past the one these images were built at. It pins get_fattime(), the FAT timestamp the device stamps on files it writes, to the published build date. The images already carry that value, so no firmware byte changes. Without it make_filetime.py re-stamps each build with the current date and the comparison fails on that single constant.
Under rootless Docker make repro aborts before it ever compares: shared.mk runs the container as $(id -u), which cannot write stm32/built, so the copy-back rsync fails first. Run the container as root, which rootless maps back to your own user.
And that the base is genuinely Coinkite's:
git fetch https://github.com/Coldcard/firmware master
git merge-base --is-ancestor FETCH_HEAD d229e5e4 && echo "built on Coinkite's master"Verified
| 142 cross-implementation vectors | from the rule's own test data, vendored byte-identical |
| Unified suites | 37 passed, 0 failed |
| Legacy regression | 108 of 108 multisig tutorial cases, 0 failed |
| Upstream baseline | the same case passes on Coinkite's 5.6.3 unmodified, so the suite itself is sound |
The rule did not change between v29.4.1 and v29.4.2: the vectors, interpreter.cpp, interpreter.h and the specification are byte-identical, so earlier verification still holds.
On hardware: the 1.5.2QU build was installed on a COLDCARD Q and used to sign.
Not verified: taproot, which this tree cannot spend; behavior on a chain where the fork is scheduled but not yet active.
No warranty
Unofficial, unaudited firmware provided as is, with no warranty and no liability, under the same terms as the LICENSE it inherits from Coinkite. Not a Coinkite product, and Coinkite does not support it. Installing it is entirely at your own risk, and you alone bear any loss of funds or loss of access to your device.
Unified opt-in sighash: 5.6.2U (Mk4/Mk5), 1.5.2QU (Q) - superseded
Superseded by the latest release. This build is sound and its verification stands; it is built on Coinkite's 5.6.2, so it does not carry their newer fixes. Its artifacts are kept so anyone holding them can still check them against the signed manifest.
COLDCARD firmware adding the unified opt-in signature hash from Bitcoin Knots, on top of Coinkite's 5.6.2 / 1.5.2Q. Built from unified-sighash at 3f78c478.
Bitcoin Knots v29.4.1.knots20260508 defines one signature message for every script type, opted into per input by hash type bit 0x20, specified in doc/unified-sighash.md. This carries no activation height and decides no consensus rules: the wallet that builds the PSBT decides which message to ask for.
Not affiliated with Coinkite. Coinkite has not adopted the fork, so use their firmware instead if that is what you want.
What it does
A PSBT may request hash types 0x21, 0x22, 0x23, 0xa1, 0xa2, 0xa3. A signature made with one commits to every spent amount and scriptPubKey rather than only the input being signed, which closes CVE-2020-14199 and CVE-2013-2292 for those inputs, and does not verify under the pre-fork rules, so the transaction cannot be replayed onto a chain without the rule.
Signing is byte-for-byte unchanged unless a PSBT asks for it.
The approval screen says what the signature covers. ANYONECANPAY has its own wording, because those commit to that input's own amount and to no other. 0x20 and 0xa0 are refused: they set the bit but name no output type.
Covers bare, P2SH and segwit v0. This tree does not sign taproot, so the rule's taproot script types are unreachable here.
Replaces the earlier builds
This is built on Coinkite's 5.6.2, released the same day, so it carries their latest fixes. The two earlier builds are withdrawn: 5.6.1U/1.5.1QU showed an approval note that was false for ANYONECANPAY, and 5.6.2U/1.5.2QU of 2026-09-03T1358 was built on 5.6.1-era code, so its version string implied a base it did not have. Their images have been removed so they cannot be flashed by mistake. If you flashed either, reflash from here.
Not signed by Coinkite
Signed with key zero, the development key published in the firmware repo, so it proves nothing about who built it. Permanently: a warning screen and forced delay on every boot, no green "genuine" light, and the main PIN is still required to install. A crash before the login sequence completes is not recoverable. Do not put this on a device holding funds you cannot afford to lose access to.
Files
| file | model | version |
|---|---|---|
2026-09-03T1617-v5.6.2U-mk-coldcard.dfu |
Mk4 / Mk5 | 5.6.2U |
2026-09-03T1617-v1.5.2QU-q1-coldcard.dfu |
Q | 1.5.2QU |
SHA256SUMS / SHA256SUMS.asc |
checksums and detached signature | |
README.md |
full verification notes |
eece4ad1bb0aa33ed54c3f17fc43294a0a17b557a8ae357a93a22eb38ab5ed8c 2026-09-03T1617-v1.5.2QU-q1-coldcard.dfu
809559b8783ee646796f34f7158ece6f2fe729c71a2d86f0159cc4dd277c070f 2026-09-03T1617-v5.6.2U-mk-coldcard.dfu
gpg --recv-keys A47D99B6DB0D715D40C59A2023AE8A8EA7E24E38
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum -c SHA256SUMSReproducing the build
Both images rebuild bit-for-bit from source. Verified with the repo's own checker, not a hand-rolled hash:
git clone https://github.com/privkeyio/cc-firmware && cd cc-firmware
git checkout f7bacde6 && git submodule update --init
cp ~/Downloads/2026-09-03T1617-v5.6.2U-mk-coldcard.dfu releases/
cd stm32 && make -f MK-Makefile repro # Q1-Makefile for the QIt ends in You have built a bit-for-bit identical copy of Coldcard firmware. check-repro splits the published DFU and diffs a full hexdump against the rebuild, excluding only the 128-byte header at 0x3f80, which holds the build timestamp and the signature over it. That is why the DFU's own hash never matches a rebuild while the firmware body does.
Reproduce from f7bacde6 on release/v5.6.2U, not from the commit these images were built at. It corrects a stale version comment in file_time.c so make_filetime.py stops regenerating the file. The constant it holds is unchanged, so no firmware byte differs. Without it get_fattime() is re-stamped with the current date, and the rebuild matched these images only on the day they were originally built.
Under rootless Docker make repro aborts before it ever compares: shared.mk runs the container as $(id -u), which cannot write stm32/built, so the copy-back rsync fails first. Run the container as root, which rootless maps back to your own user.
And that the base is genuinely Coinkite's:
git fetch https://github.com/Coldcard/firmware master
git merge-base --is-ancestor FETCH_HEAD f7bacde6 && echo "built on Coinkite's master"Verified
| 142 cross-implementation vectors | from the rule's own test data, vendored byte-identical |
| Unified suites | 55 passed, 0 failed |
| Regression | 108 of 108 multisig tutorial cases, 0 failed |
| Reviews | code review, security review, and a re-review of the fixes |
All on this base. Mainnet is past the fork's activation height, so opted-in signatures are valid on mainnet now.
On hardware: 1.5.2QU has been installed on a COLDCARD Q and used to sign a mainnet transaction carrying the opt-in. The Mk4/Mk5 build shares the same firmware and was built the same way, but has not been run on that hardware.
Not verified: Mk4/Mk5 hardware; taproot, which this tree cannot spend; behavior on a chain where the fork is scheduled but not yet active.
No warranty
Unofficial, unaudited firmware provided as is, with no warranty and no liability, under the same terms as the LICENSE it inherits from Coinkite. Not a Coinkite product, and Coinkite does not support it. Installing it is entirely at your own risk, and you alone bear any loss of funds or loss of access to your device.
5.6.2U / 1.5.2QU, 5.6.1-based - withdrawn, use the latest release
Withdrawn. Use the latest release instead.
This build fixed the approval-screen defect in the previous release, but it was built on COLDCARD 5.6.1 / 1.5.1Q-era code hours before Coinkite released 5.6.2. Its version string therefore implied a base it did not have, and it does not carry the 56 upstream commits in 5.6.2, several of which are security fixes.
The current release is built on Coinkite's 5.6.2 and uses the same version strings, which are now accurate.
The images have been removed so they cannot be flashed by mistake. If you flashed one, reflash from the current release. No key material is at risk.
No warranty
This is unofficial, unaudited firmware provided as is, with no warranty and no liability, under the same MIT-style Coinkite license it inherits. It is not a COLDCARD release and is neither affiliated with nor supported by Coinkite. Flashing it is entirely at your own risk, and you alone bear any loss of funds or loss of access to your device.
5.6.1U / 1.5.1QU - withdrawn, use the latest release
Withdrawn. Use the latest release instead.
The approval screen said Commits to every input amount, not just this one (sighash UNIFIED). for every opted-in input. That is true for hash types 0x21, 0x22 and 0x23. It is false for 0xa1, 0xa2 and 0xa3, where the message commits to that input's own spent output and to no other. A host could set your input to unified ANYONECANPAY, leave a sibling input under its control, and the screen would tell you that you were covered against exactly the amount-substitution attack the opt-in exists to close.
Reaching it needs a PSBT that asks for one of those three types. Ordinary ALL|UNIFIED signing showed the correct text, so the risk was to anyone signing a PSBT built to exploit it.
This build is also based on COLDCARD 5.6.1 / 1.5.1Q, and Coinkite has since released 5.6.2 with security fixes it does not carry.
The images have been removed so they cannot be flashed by mistake. If you flashed one, reflash from the current release. No key material is at risk: the defect was in what the approval screen claimed, not in the signature or in how keys are handled, so seeds that only ever sat on a device running this build do not need to be moved.
No warranty
This is unofficial, unaudited firmware provided as is, with no warranty and no liability, under the same MIT-style Coinkite license it inherits. It is not a COLDCARD release and is neither affiliated with nor supported by Coinkite. Flashing it is entirely at your own risk, and you alone bear any loss of funds or loss of access to your device.