v2: Return HTTP 400 for JSON completion errors without relaxing rejection - #3629
vortexopenclaw wants to merge 5 commits into
Conversation
Keep REQBODY_ERROR and its diagnostic when JSON parsing fails at EOF, without converting the completed body read into an unconditional HTTP 500. This aligns completion errors with chunk-time JSON errors and leaves the configured rule in control of the response. Add Apache regression coverage for configurable denial, detection-only and non-disruptive policies, valid and empty bodies, in-stream errors, argument inspection, and chunked input. Related to owasp-modsecurity#2807.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (4)
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughRequest-body processing now separates limit and bucket handling. JSON completion errors return a distinct code that maps to HTTP 400. Regression tests cover body limits, chunked requests, premature JSON EOF, parser errors, and YAJL-disabled builds. ChangesRequest body processing
Priority: ⬇️ Low Estimated code review effort: 4 (Complex) | ~60 minutes Change: Bug fix Merge Risk: ⚪ Minimal · up to The change preserves request-body limit behavior while returning 400 for JSON completion failures, with no concrete unresolved merge risk identified. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Replace the earlier rule-controlled proposal with a conservative JSON-only status correction. Preserve unconditional rejection, including when the error policy is absent, excluded, non-disruptive or DetectionOnly. Leave XML, multipart, streaming errors and generic failures unchanged. Adapt the JSON portion of the return-code approach proposed by Marc Stern in upstream PR owasp-modsecurity#3515. Add explicit fail-closed, opt-out and optional-YAJL regression coverage. Related to owasp-modsecurity#2807 and owasp-modsecurity#3515.
Use a switch for the explicit -5 and -2 completion results, retaining the generic negative-result fallback. This preserves the tested status mapping and avoids increasing the existing request reader cognitive complexity flagged by SonarCloud.
There was a problem hiding this comment.
🔵 Needs a closer look
Security-sensitive request-body handling and outstanding upstream CI/quality gates require maintainer review.
Pull request overview
Updates ModSecurity v2 to return HTTP 400 for JSON completion failures while preserving unconditional rejection and JSON inspection.
Changes:
- Adds a distinct JSON completion-failure result.
- Maps completion failures to HTTP 400.
- Adds comprehensive regression coverage.
File summaries
| File | Description |
|---|---|
tests/regression/rule/15-json-eof.t |
Adds JSON completion and rejection regression tests. |
apache2/msc_reqbody.c |
Identifies JSON completion failures separately. |
apache2/apache2_io.c |
Maps JSON completion failures to HTTP 400. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Separate bucket reads, nonempty chunk storage and whole-body limit handling. Collapse repeated limit diagnostics while preserving the distinct no-files limit policy, stream compile-time paths, byte accounting, EOS state and completion status mapping. Add 24 native chunked boundary tests across both engines and limit actions, validated against the pre-refactor implementation. This addresses the SonarCloud cognitive-complexity finding without suppressing it.
|
@coderabbitai review |
✅ Action performedReview finished.
|
|



Summary
Problem: ModSecurity v2 rejects an incomplete JSON request with 500 Internal Server Error before phase 2 runs. The request is rejected, but the response incorrectly reports a server failure.
Fix: Return 400 Bad Request for JSON completion failures while preserving the existing unconditional rejection. JSON inspection stays enabled. Missing, excluded, log-only, or DetectionOnly error policies do not cause previously rejected requests to reach the application.
This is a deliberately conservative status-code correction, not a change to who controls JSON error policy.
Review status: ready for maintainer review, not merge-cleared. SonarCloud now passes with no open issues. The standard-build local suites below pass. The current-head Linux/IIS workflows need upstream approval; CodeRabbit completed review with no actionable comments. Supplemental optional-build limitations are stated separately below.
Relationship to #3515
PR #3515, carrying Marc Stern's proposed change, already implements the same return-code approach. This PR adapts its JSON portion; it is overlapping work, not a separate discovery or a second patch that needs to be merged alongside it.
For the JSON case, this revision intentionally agrees with #3515. Its additional value is the narrower parser-status scope and regression evidence. The supporting shared-reader refactor broadens the implementation diff and is independently compared against the pre-refactor revision. The tests can also be reused with #3515 if maintainers prefer that broader proposal.
Design decision and tradeoffs
An earlier revision removed the early return so
REQBODY_ERRORrules could choose the outcome. Comparative testing showed that it also forwarded incomplete JSON when no effective blocking rule applied. I replaced that design rather than treating the compatibility change as incidental to a status-code fix.Limitations retained: Completion failures still do not run phase 2, do not honor a custom phase-2 response, and still reject in DetectionOnly. In-stream JSON syntax errors continue using the existing rule-controlled path. This does not resolve the broader request for configurable error handling discussed in #2807; that would be a separate intentional compatibility decision.
Implementation
-2from the existing built-in JSON completion-failure branch inmodsecurity_request_body_end().HTTP_BAD_REQUESTinread_request_body(), preserving the-5→ 413 and other negative results → 500 mappings.“Completion failure” includes a parser/callback failure detected while finishing the JSON document, not solely premature EOF. No new dependencies, options or parsing work are introduced.
Verification
Base:
v2/masterat0875b1928003fa77ad5d2dcd61c531149ded7781(2.9.14). Comparison patch: #3515 ata97a84b56cd1b2289be07bcb9ea11a0e358a8e01. Environment: Ubuntu 24.04 arm64, Apache 2.4.58, YAJL 2.1.0, GCC and PCRE2. All HTTP tests ran on container loopback with external networking disabled and no published ports.--without-yajl; all 14 JSON cases pass their explicit no-YAJL expectations; all 24 new bucket/limit cases also pass. Enabled-parser builds still require the strict parser-error/status/phase-2 assertions.--enable-large-stream-input. A 384-request comparison found zero pre/post differences, but reproduced an existing failure in both versions. This is not counted as an all-passing optional-build suite; that limitation needs separate maintainer/security triage. The standard-build results above do not use this optional mode.Reproduce the native suites after checking out this revision and initializing the pinned submodule:
./autogen.sh ./configure --enable-pcre-study=yes --enable-pcre-jit CFLAGS=-Werror=format-security make -j4 make test make test-regressionThe direct HTTP runner used in the root-owned isolated container was
USER=root LOGNAME=root perl run-regression-tests.pl -S . -p 8090 -vfromtests/. Use the actual test-process user forUSER/LOGNAME. Repeat the focusedregression/rule/15-json-eof.tfile in a separate--without-yajlbuild to exercise optional-parser behavior.Automated review and remaining gates
59b1dfe924438215198756429b4e87d21bd208c3; the issue API reports zero open issues. The reader was refactored rather than adding a suppression or changing the quality gate.59b1dfe, covering all four changed files, with no actionable comments. Its successful status is now a completed review, not a skip. This is not a substitute for maintainer approval.Independent design/security review found no new implementation blocker in the refactor; standard-build differential and regression evidence is above. This does not certify every supported build or erase the separately observed optional-build failure. Maintainer review and successful current-head cross-platform CI remain merge prerequisites. No production deployment is included.
Related: #2807, #3515. The partial-body redesign in #3483 is outside this change.