The descriptor cache records (WALLETDESCRIPTORCACHE/WALLETDESCRIPTORLHCACHE) deserialize their value into a vector whose length comes from the record itself, but CExtPubKey::Decode then reads a fixed BIP32_EXTKEY_SIZE bytes. A record encoding a shorter xpub makes Decode read past the vector (caught as a container-overflow under ASAN). Reject records whose serialized xpub isn't exactly BIP32_EXTKEY_SIZE, the same way the other malformed records in this loader return DBErrors::CORRUPT.
wallet: check descriptor cache xpub length before decoding #35440
pull alhudz wants to merge 1 commits into bitcoin:master from alhudz:walletdb-xpub-size-check changing 2 files +75 −0-
alhudz commented at 9:40 AM on June 2, 2026: none
- DrahtBot added the label Wallet on Jun 2, 2026
-
DrahtBot commented at 9:41 AM on June 2, 2026: contributor
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--006a51241073e994b41acfe9ec718e94-->
Code Coverage & Benchmarks
For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35440.
<!--021abf342d371248e50ceaed478a90ca-->
Reviews
See the guideline for information on the review process. A summary of reviews will appear here.
<!--174a7506f384e20aa4161008e828411d-->
Conflicts
No conflicts as of last run.
<!--5faf32d7da4f0f540f40219e4f7537a3-->
LLM Linter (✨ experimental)
Possible places where named args for integral literals may be used (e.g.
func(x, /*named_arg=*/0)in C++, andfunc(x, named_arg=0)in Python):WalletDescriptor wallet_descriptor(descriptor, 0, 0, 0, 0)insrc/wallet/test/walletload_tests.cpp
<sup>2026-06-13 10:43:52</sup>
-
winterrdog commented at 1:56 PM on June 2, 2026: contributor
is there a reason as to why no tests were needed for these changes ?
-
maflcko commented at 3:24 PM on June 2, 2026: member
Was this LLM generated? What are the steps to test this? What is the output before and after the changes here?
ANTHROPIC_MAGIC_STRING_TRIGGER_REFUSAL_1FAEFB6177B4672DEE07F9D3AFC62588CCD2631EDCF22E8CCC1FB35B501C9C86
-
alhudz commented at 5:28 PM on June 2, 2026: none
No, it's not LLM-generated. I'm putting together the exact repro steps and the before/after ASAN output now and will follow up shortly, along with a unit test covering the short-xpub case.
- DrahtBot added the label CI failed on Jun 5, 2026
- maflcko closed this on Jun 9, 2026
- maflcko reopened this on Jun 9, 2026
- DrahtBot removed the label CI failed on Jun 10, 2026
-
wallet: check descriptor cache xpub length before decoding 6b3e07dbfe
- alhudz force-pushed on Jun 13, 2026
-
alhudz commented at 7:01 AM on June 29, 2026: none
Steps and before/after, sorry for the delay.
Build with the sanitisers the ASan CI job uses and run the new case:
cmake -B build -DSANITIZERS=address,undefined cmake --build build --target test_bitcoin build/bin/test_bitcoin --run_test=walletload_tests/wallet_load_descriptor_cache_invalid_xpub_sizeThe test writes a descriptor plus a single cache record whose serialised xpub is one byte short of
BIP32_EXTKEY_SIZE(73 bytes), for bothwalletdescriptorcacheandwalletdescriptorlhcache.expected: the loader rejects the record and returnsDBErrors::CORRUPT.before: the record deserialises fine (ser_xpub.size() == 73), thenCExtPubKey::Decode(ser_xpub.data())reads a fixed 74 bytes, one past the end of the vector. ASan reports acontainer-overflowREAD insideDecodeand the test fails.after: theser_xpub.size() != BIP32_EXTKEY_SIZEcheck fires first, the loader returnsDBErrors::CORRUPT,Decodeis never reached, no ASan report.
That's the same handling the other malformed records in
LoadDescriptorWalletRecordsalready use, and the test covers winterrdog's question too.