When the XML body processor fails, REQBODY_ERROR_MSG and the debug log
only said "XML: Failed to parse document." libxml2 knows the actual
reason (tag mismatch, extra content, empty document, ...) with line and
column, and until 3.0.15 that text leaked to stderr by accident.
Read xmlCtxtGetLastError() after a failed xmlParseChunk() and build the
message from it:
XML: Failed to parse document: Opening and ending tag mismatch:
book line 1 and bookasdf (line 1, column 725)
The fixed text stays as the fallback when libxml2 has no message. The
same applies to the ARGS parsing context. xmlCtxtGetLastError() is
available and non-deprecated on every libxml2 we build against
(checked 2.9.13 and 2.15.4) and keeps working under XML_PARSE_NOERROR,
so no version conditionals are needed.
Adds a regression case that matches REQBODY_ERROR_MSG on the libxml2
text and asserts the debug log line.
Fixes owasp-modsecurity#3678
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
what
When the XML request body processor fails,
REQBODY_ERROR_MSGand the debug log now carry libxml2's own reason, with line and column, instead of the fixedXML: Failed to parse document.:Implementation: after a failed
xmlParseChunk(), readxmlCtxtGetLastError()on the context and build the message from itsmessage,lineandint2fields. The fixed text remains as the fallback when libxml2 has no message. The same is done for the ARGS parsing context. Incomplete()the error is read beforexmlFreeParserCtxt().why
Until 3.0.15 this detail leaked to stderr by accident (#3563). #3677 silences that properly, so without this change the reason is lost entirely. Operators debugging rule 200002 hits often cannot capture bodies (PCI), and the libxml2 message alone usually tells whether it was a truncated body, a wrong
Content-Type, or a probe. Rule writers can also matchREQBODY_ERROR_MSGon it.xmlCtxtGetLastError()is available and non-deprecated on every libxml2 we build against (checked 2.9.13 and 2.15.4), and the 2.15 headers state errors stay accessible through it underXML_PARSE_NOERROR. NoLIBXML_VERSIONconditionals and no SAX or structured-error callback.Independent of #3677 in code; either can merge first.
tests
New case in
variable-REQBODY_PROCESSOR_ERROR.json: a rule matchingREQBODY_ERROR_MSGwith@contains Opening and ending tag mismatch: book line 1 and bookasdfdenies with 403, and the debug log is asserted with a regex that leaves the column number free. Fails onv3/master(200, generic message), passes with this change.make checkotherwise unchanged (only the 9 pre-existingremoveCommentsfailures from the submodule mismatch). The file also compiles clean against libxml2 2.15.4 headers.references
Fixes #3678. Related: #3563, #3677.
🤖 Generated with Claude Code
Summary by CodeRabbit