# CashAddr::Decode() OOB # ---------------------- Responsible Disclosure By: Roqqit Bounties appreciated: ecash:qpd0f2pkz5pvz9m8vktk5m9kp54klk7wa5eumecdhj bitcoincash:qqfnucw5hu0eudpuh5vpprd0c8w7q9ya8q0yng27pl bc1qhaxsclfel39vl8gztf7cegxymy82v8qh8lj4lp # Impact Trivially triggerable out-of-bounds (OOB) in cashaddr::Decode() may trigger a crash. Initial code review suggests it is not p2p reachable and RPC calls are appropriately caught so the node does not crash. However, risk to the codebase remains high. Note that while the primary software identified is the node software, associated CashAddr libraries derived from the node implementation may be affected. PLEASE NOTE THAT THE IMPACT AND SEVERITY ARE LIKELY TO BE HIGHER HERE IF THE CRASH PRESENTS ITSELF TO END USERS. # Affected Software BLOCKCHAIN SOFTWARE ----------------------------------------- eCash (XEC) [Bitcoin ABC Node](https://github.com/Bitcoin-ABC/bitcoin-abc/tree/master/src) eCash (XEC) [Bitcoin ABC CKPool](https://github.com/Bitcoin-ABC/ecash-ckpool-solo) eCash (XEC) [Bitcoin ABC Trezor Firmware](https://github.com/Bitcoin-ABC/ecash-trezor-firmware) eCash (XEC) + Bitcoin Cash (BCH) [Trezor Firmware](https://github.com/trezor/trezor-firmware) Bitcoin Cash (BCH) [Bitcoin Cash Node](https://gitlab.com/bitcoin-cash-node/bitcoin-cash-node) # Suggested Remedy: Correctly validate cashaddr length to be a minimum of 8 characters to accomodate the checksum size of 8 bytes. 1. Apply a fix to the node software and cut a release immediately. 2. Identify affected libraries and other exogenous software (wallets, mining pools, etc.) with implementations derived from cashaddr::Decode(). 3. Prioritize fixing affected software by highest severity first. # Vulnerability Details At a high-level, cashaddr::Decode() does not appropriately validate the checksum length to be 8 bytes. It is possible to generate an address with a checksum shorter than 8 bytes that passes initial checksum checks, that later triggers an out-of-bounds, resulting in a `std::length_error: cannot create std::vector larger than max_size()` in cashaddr.cpp:289 which reads: ``` return {std::move(prefix), data(values.begin(), values.end() - 8)}; ``` Bitcoin ABC fixed this vulnerability in commit 8b31fb4780 ## Proof of Concept This proof of concept patch demonstrates the issue when applied to the Bitcoin ABC codebase: ``` diff --git a/src/test/cashaddr_tests.cpp b/src/test/cashaddr_tests.cpp index f8c0022192..78ef7ae64c 100644 --- a/src/test/cashaddr_tests.cpp +++ b/src/test/cashaddr_tests.cpp @@ -90,4 +90,19 @@ BOOST_AUTO_TEST_CASE(cashaddr_testvectors_noprefix) { } } +BOOST_AUTO_TEST_CASE(cashaddr_decode_short_payload_security) { + // SECURITY PoC: these strings have a VALID checksum but a payload of + // fewer than 8 characters (the checksum length). Decode must reject them + // by returning an empty prefix. Currently `values.end() - 8` underflows + // (UB) and std::vector range construction throws std::length_error. + // + // "rqiqkqiqr:" has an EMPTY payload (PolyMod(ExpandPrefix("rqiqkqiqr")) + // == 0). "c:qvdy2z3" has a 7-char payload with a valid checksum. + for (const std::string &str : {"rqiqkqiqr:", "c:qvdy2z3"}) { + std::pair> result; + BOOST_CHECK_NO_THROW(result = CashAddrDecode(str)); + BOOST_CHECK_MESSAGE(result.first.empty(), str); + } +} + BOOST_AUTO_TEST_SUITE_END() ``` ## Test Vectors These additional test vectors were copied from ABC commit 8b31fb4780, the same as the fix, and are recommended at a minimum: ``` "", ":", "p", "p:", "p:g", "p:gp", "p:gpf", "p:gpf8", "p:gpf8m", "p:gpf8m4", "p:gpf8m4h", "rpzrrzpr:", "rqiqkqiqr:", "c:qvdy2z3", ``` # EDITED 2026-08-27: Added other affected Bitcoin ABC softwares # EDITED 2026-08-28: Added Trezor Firmware to affected softwares