Skip to content

feat: surface libxml2's parse error in REQBODY_ERROR_MSG - #3679

Open
fzipi wants to merge 1 commit into
owasp-modsecurity:v3/masterfrom
fzipi:v3/issue-3678-xml-error-message
Open

fzipi wants to merge 1 commit into
owasp-modsecurity:v3/masterfrom
fzipi:v3/issue-3678-xml-error-message

Conversation

@fzipi

@fzipi fzipi commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

what

When the XML request body processor fails, REQBODY_ERROR_MSG and the debug log now carry libxml2's own reason, with line and column, instead of the fixed XML: Failed to parse document.:

XML: Failed to parse document: Opening and ending tag mismatch: book line 1 and bookasdf (line 1, column 725)

Implementation: after a failed xmlParseChunk(), read xmlCtxtGetLastError() on the context and build the message from its message, line and int2 fields. The fixed text remains as the fallback when libxml2 has no message. The same is done for the ARGS parsing context. In complete() the error is read before xmlFreeParserCtxt().

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 match REQBODY_ERROR_MSG on 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 under XML_PARSE_NOERROR. No LIBXML_VERSION conditionals 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 matching REQBODY_ERROR_MSG with @contains Opening and ending tag mismatch: book line 1 and bookasdf denies with 403, and the debug log is asserted with a regex that leaves the column number free. Fails on v3/master (200, generic message), passes with this change. make check otherwise unchanged (only the 9 pre-existing removeComments failures 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

  • Bug Fixes
    • XML parsing failures now provide more specific error details, including the error message and location when available.
    • Added regression coverage for malformed XML error reporting and HTTP 403 handling.

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>
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 68deb485-232e-4415-8afa-c176bd0f6f3b
📥 Commits

Reviewing files that changed from the base of the PR and between 48e561b and f062f5f.

📒 Files selected for processing (2)
  • src/request_body_processor/xml.cc
  • test/test-cases/regression/variable-REQBODY_PROCESSOR_ERROR.json

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.

📝 Walkthrough

The XML body processor now includes libxml2’s parse message and location in document and ARGS parse errors when available. A regression case checks the detailed error in the debug log and in REQBODY_ERROR_MSG, and expects HTTP 403.

Changes: XML parse error reporting

Layer / File(s) Summary
Format and report XML parse errors
src/request_body_processor/xml.cc, test/test-cases/regression/variable-REQBODY_PROCESSOR_ERROR.json
The processor formats libxml2 error details with line and column information and uses them for document and ARGS parse failures. The regression case checks the mismatch message and HTTP 403 response.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Feature · Severity of issue fixed: Medium

Suggested reviewers: airween

Merge Risk: ⚪ Minimal · up to f062f

The XML error-reporting change has no identified merge-blocking issue; proceed with normal checks.

Pre-merge checks · Passed 4 · Failed 1

Failed Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 1 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks (4 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: exposing libxml2 parse errors in REQBODY_ERROR_MSG.
Linked Issues check Passed Issue #3678 requires libxml2 diagnostics in REQBODY_ERROR_MSG and the debug log for document and ARGS parsing failures. src/request_body_processor/xml.cc adds parseError(), which reads `xmlCtxtGet…
Out of Scope Changes check Passed The changes are limited to XML parse-error formatting in src/request_body_processor/xml.cc and a regression test in test/test-cases/regression/variable-REQBODY_PROCESSOR_ERROR.json. These changes …
Full details: Docstring Coverage

Explanation

Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 1 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

@airween airween added the 3.x Related to ModSecurity version 3.x label Oct 13, 2026
@airween airween self-assigned this Oct 13, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3.x Related to ModSecurity version 3.x

Projects

None yet

Development

Successfully merging this pull request may close these issues.

XML body processor: surface libxml2's parse error in REQBODY_ERROR_MSG and the debug log

2 participants