What changed, and why it matters
This commit removes user-controlled JSON content from error and log messages in Monero's epee networking/serialization library. Previously, when the JSON parser failed, it would copy parts of the raw request into log files or error strings. A malicious user could craft JSON containing fake log entries, terminal escape sequences, or misleading text, which might then be written to logs or shown to administrators. The fix replaces those messages with fixed, safe descriptions and escapes any exception text before logging it.
Treat as a low-to-moderate security hardening fix. Review whether transform_to_escape_sequence fully neutralizes relevant control characters, and confirm that upstream logging frameworks are not still vulnerable to injection elsewhere. No immediate emergency response is indicated, but backporting to maintained release branches is reasonable.
Security signals we found
Log injection via unsanitized attacker-controlled data in error/log messages
JSON parser error paths echoing raw input back into logs
Unknown JSON escape sequences previously logged and accepted instead of rejected
Exception messages logged without escaping
Evidence from the diff
The patch addresses log injection and related parser-hardening issues in contrib/epee. It stops embedding attacker-controlled JSON snippets (query_info.m_body, iterator ranges from the input buffer) in log/error messages. It also changes handling of unknown escape sequences from a log-and-continue to an exception, and sanitizes exception text via transform_to_escape_sequence before logging. The changes span HTTP server handler mapping, portable_storage JSON parsing, and parser base utilities.
Changed components
contrib/epee/include/net/http_server_handlers_map2.hcontrib/epee/include/storages/portable_storage_from_json.hcontrib/epee/src/parserse_base_utils.cppInspect captured patch +12 / −13
diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h
index 92aaa95..49bd5a8 100644
--- a/contrib/epee/include/net/http_server_handlers_map2.h
+++ b/contrib/epee/include/net/http_server_handlers_map2.h
@@ -72,7 +72,7 @@
bool parse_res = epee::serialization::load_t_from_json(static_cast<command_type::request&>(req), query_info.m_body); \
if (!parse_res) \
{ \
- MERROR("Failed to parse json: \r\n" << query_info.m_body); \
+ MERROR("Failed to parse JSON request"); \
response_info.m_response_code = 400; \
response_info.m_response_comment = "Bad request"; \
return true; \
diff --git a/contrib/epee/include/storages/portable_storage_from_json.h b/contrib/epee/include/storages/portable_storage_from_json.h
index 908e830..d9df576 100644
--- a/contrib/epee/include/storages/portable_storage_from_json.h
+++ b/contrib/epee/include/storages/portable_storage_from_json.h
@@ -43,7 +43,7 @@ namespace epee
{
namespace json
{
-#define CHECK_ISSPACE() if(!epee::misc_utils::parse::isspace(*it)){ ASSERT_MES_AND_THROW("Wrong JSON character at: " << std::string(it, buf_end));}
+#define CHECK_ISSPACE() if(!epee::misc_utils::parse::isspace(*it)){ ASSERT_MES_AND_THROW("Unexpected character in JSON data");}
/*inline void parse_error()
{
@@ -168,7 +168,7 @@ namespace epee
{
//sub section here
typename t_storage::hsection new_sec = stg.open_section(name, current_section, true);
- CHECK_AND_ASSERT_THROW_MES(new_sec, "Failed to insert new section in json: " << std::string(it, buf_end));
+ CHECK_AND_ASSERT_THROW_MES(new_sec, "Failed to insert new section in JSON data");
run_handler(new_sec, it, buf_end, stg, recursion + 1);
state = match_state_wonder_after_value;
}else if(*it == '[')
@@ -403,7 +403,7 @@ namespace epee
}
catch(const std::exception& ex)
{
- MERROR("Failed to parse json, what: " << ex.what());
+ MERROR("Failed to parse json, what: " << misc_utils::parse::transform_to_escape_sequence(ex.what()));
return false;
}
catch(...)
diff --git a/contrib/epee/src/parserse_base_utils.cpp b/contrib/epee/src/parserse_base_utils.cpp
index 7f7f2f2..171b4de 100644
--- a/contrib/epee/src/parserse_base_utils.cpp
+++ b/contrib/epee/src/parserse_base_utils.cpp
@@ -176,8 +176,7 @@ namespace misc_utils
}
break;
default:
- val.push_back(*it);
- LOG_PRINT_L0("Unknown escape sequence :\"\\" << *it << "\"");
+ ASSERT_MES_AND_THROW("Invalid escape sequence in JSON string");
}
escape_mode = false;
}else if(*it == '"')
@@ -187,13 +186,13 @@ namespace misc_utils
}else if(*it == '\\')
{
escape_mode = true;
- }
+ }
else
{
val.push_back(*it);
}
}
- ASSERT_MES_AND_THROW("Failed to match string in json entry: " << std::string(star_end_string, buf_end));
+ ASSERT_MES_AND_THROW("Unterminated JSON string");
}
void match_number2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val, bool& is_float_val, bool& is_signed_val)
{
@@ -226,10 +225,10 @@ namespace misc_utils
return;
}
else
- ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
+ ASSERT_MES_AND_THROW("Invalid number in JSON entry");
}
}
- ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
+ ASSERT_MES_AND_THROW("Invalid number in JSON entry");
}
void match_word2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val)
{
@@ -244,11 +243,11 @@ namespace misc_utils
{
star_end_string = --it;
return;
- }else
- ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
+ }else
+ ASSERT_MES_AND_THROW("Invalid word in JSON entry");
}
}
- ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
+ ASSERT_MES_AND_THROW("Invalid word in JSON entry");
}
}
}
Why this scored 51/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.