From b3e81f1eda68bcd79cac0ec6e11c6e00ceb0fc9a Mon Sep 17 00:00:00 2001 From: DanS Date: Fri, 28 Aug 2026 23:30:24 -0500 Subject: [PATCH] stratum: do not abort the daemon on a malformed 63-character job_id The "EWBF 31 bytes job_id fix" in stratum_mining_submit completes a 63-character job_id with each hex digit in turn and feeds the result straight to uint256(). ParseHex() stops at the first non-hex character and returns a shorter vector without signalling an error, and base_blob(const std::vector&) asserts vch.size() == 32. So a single mining.submit whose job_id is any 63-character string containing a non-hex byte -- 63 spaces will do -- aborts the node. asserts are live in release builds here: -DNDEBUG appears only in leveldb's own makefile, never in configure.ac, and the shipped binary still carries the assertion string. The dispatch loop catches UniValue and std::exception; abort() goes through both. Size-check each candidate before constructing, as ParseUInt256() a few hundred lines up already does for the ordinary path. If none of the 16 completions parse, ret stays null, misses work_templates, and the handler returns false exactly as it does for any unknown job. Not gated on IsHex(job_id_str): 63 is odd and IsHex() requires an even length, so that test would disable the EWBF path this code exists for. --- src/stratum.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/stratum.cpp b/src/stratum.cpp index 42e31a10d..16736e6e2 100644 --- a/src/stratum.cpp +++ b/src/stratum.cpp @@ -1334,7 +1334,16 @@ UniValue stratum_mining_submit(StratumClient& client, const UniValue& params) if (job_id_str.length() == 63) { fEWBFJobIDFixNeeded = true; for(const auto& hexDigit : hexDigits) { - ret = uint256(ParseHex(job_id_str + hexDigit)); + // ParseHex() stops at the first non-hex character and returns a SHORT vector + // without signalling an error, and base_blob(const std::vector&) + // asserts vch.size() == 32. Constructing without checking therefore lets any + // 63-character job_id containing a non-hex byte abort the daemon -- from an + // unauthenticated client, before any other validation. Skip bad candidates + // instead; if none of the 16 completions parse, ret stays null, misses + // work_templates below, and the handler returns false cleanly. + std::vector vch = ParseHex(job_id_str + hexDigit); + if (vch.size() != 32) continue; + ret = uint256(vch); if (work_templates.count(ret)) break; } }