What changed, and why it matters
This commit fixes how Monero's automatic update checker validates the cryptographic hash of a downloaded update. Previously, the code only checked that the hash string was 64 characters long and contained only letters or digits. That check was flawed: a 64-character hex string with only alphanumeric characters would pass even if it was not a valid hash, and the hash was never converted into a proper internal hash object. The patch now converts the hex string into a real cryptographic hash and then back to a normalized hex form, ensuring only correctly formatted hashes are accepted. This reduces the risk that a malicious or malformed update descriptor could trick the client into trusting a bad update.
Treat this as a security hardening fix and include it in the next release. Users who rely on the built-in update notification mechanism should upgrade. Review whether update descriptors are authenticated beyond hash validation, since DNS or update-server compromise could still inject malicious metadata.
Security signals we found
Weak input validation on security-critical hash field
Hash string accepted based on length and alphanumeric check rather than cryptographic parsing
Patch replaces manual validation with strict hex-to-hash conversion
Potential for update metadata poisoning if untrusted descriptor channel is compromised
Evidence from the diff
In src/common/updates.cpp, the update metadata parser previously validated the update hash with a weak check: it required fields[3] to be 64 bytes and alphanumeric. The logic was also inverted in effect because a 64-character all-alphanumeric string passed regardless of whether it represented a valid hash. The patch replaces this with epee::string_tools::hex_to_pod(), which parses the hex string into a crypto::hash, and then re-serializes it with pod_to_hex(). This enforces strict hex decoding, normalizes the representation, and prevents acceptance of malformed or non-hex hash strings in update descriptors fetched from DNS/update sources.
Changed components
src/common/updates.cppMonero automatic update checkerUpdate hash validation pathInspect captured patch +4 / −5
diff --git a/src/common/updates.cpp b/src/common/updates.cpp
index 6c445ca..52b4932 100644
--- a/src/common/updates.cpp
+++ b/src/common/updates.cpp
@@ -28,6 +28,7 @@
#include <boost/algorithm/string.hpp>
#include "misc_log_ex.h"
+#include "string_tools.h"
#include "util.h"
#include "dns_utils.h"
#include "updates.h"
@@ -71,15 +72,13 @@ namespace tools
if (software != fields[0] || buildtag != fields[1])
continue;
- bool alnum = true;
- for (auto c: fields[3])
- if (!isalnum(static_cast<unsigned char>(c)))
- alnum = false;
- if (fields[3].size() != 64 && !alnum)
+ crypto::hash parsed_hash;
+ if (!epee::string_tools::hex_to_pod(fields[3], parsed_hash))
{
MWARNING("Invalid hash: " << fields[3]);
continue;
}
+ fields[3] = epee::string_tools::pod_to_hex(parsed_hash);
// use highest version
if (found)
Why this scored 61/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.