Skip to content

Conversation

@hnakamur
Copy link
Contributor

what

  • This pull request prevents a parse error that occurs when SecRequestBodyLimitAction is set to ProcessPartial and the length of an XML or JSON request body exceeds the configured limit.

why

  • When SecRequestBodyLimitAction is ProcessPartial, the expected behavior is to process the partial XML, JSON, or multipart body up to the defined limit.
  • The request should then be rejected if any invalid values are found within that processed part, or passed through if the processed part is valid.
  • The previous implementation failed to handle the partial body correctly, leading to a parse error when the limit was exceeded.

references

The same modification for v3 is at: #3476

…ssing"

Due to the previous change, the "no final boundary missing" error never
occurs when SecRequestBodyLimitAction is ProcessPartial.
Adjust the expected error message to match the message changes
introdueced in:
owasp-modsecurity@dfbde55
But reject incomplete epilogue when body fits in limit.
@airween
Copy link
Member

airween commented Dec 31, 2025

Hi @hnakamur,

thanks for this PR too.

  • When SecRequestBodyLimitAction is ProcessPartial, the expected behavior is to process the partial XML, JSON, or multipart body up to the defined limit.

I think SecRequestBodyLimitAction regards not only for XML, JSON or multipart bodies - but also to www-url-encoded body too. Consider this setup:

SecRequestBodyLimitAction ProcessPartial
SecRequestBodyNofilesLimit 10

and the payload:

aaa=123&bbb=123

then the aaa variable must have seen in ARGS with value 123.

@dune73 what do you think?

The request should then be rejected if any invalid values are found within that processed part, or passed through if the processed part is valid.

How can we be sure that the payload is valid, if the error is in the chunked part? Eg. consider the config above and this JSON:

{"a":1,"b":2,[1]]}

(the second ] makes the JSON non well-formed, but the key a must have seen in ARGS).

You helped me in #3456, which isn't merged yet (I'm waiting for a review and an approve). But could you add a new test case to the v2's source tree?

@hnakamur
Copy link
Contributor Author

hnakamur commented Jan 1, 2026

Hello @airween. Thanks for your comment.

I added tests for url-encoded, JSON, and XML request bodies. It appears that the URL-encoded parser already works as expected with ProcessPartial.

By the way, I realized that it would be better to add more tests for multipart requests. I think it will take me a day or two to do so.

hnakamur added a commit to hnakamur/ModSecurity that referenced this pull request Jan 1, 2026
This check is added to satisfy SonarQube Cloud Quality Gate on CI.
owasp-modsecurity#3483 (comment)
hnakamur added a commit to hnakamur/ModSecurity that referenced this pull request Jan 1, 2026
hnakamur added a commit to hnakamur/ModSecurity that referenced this pull request Jan 1, 2026
@hnakamur hnakamur force-pushed the v2/stop_processing_after_reqbody_limit_for_process_partial branch 2 times, most recently from 5b38984 to 0bfb828 Compare January 1, 2026 14:39
@hnakamur
Copy link
Contributor Author

hnakamur commented Jan 6, 2026

It appears that the URL-encoded parser already works as expected with ProcessPartial.

I was mistaken about that. I modified the URL-encoded parser to include names and values up to the delimiter before the limit when SecRequestBodyLimitAction is set to ProcessPartial and the request body exceeds SecRequestBodyLimit.

I also modified the multipart parser to include parts whose boundary appears before the limit under the same conditions.

In addition, I added tests to cover these changes.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes a bug where SecRequestBodyLimitAction ProcessPartial would cause parse errors when the request body exceeded the configured limit for XML, JSON, and multipart content types. The implementation enables parsers to gracefully handle truncated bodies by allowing partial/ill-formed data when the limit is exceeded.

Changes:

  • Added modsecurity_request_body_enable_partial_processing() function to enable partial processing for different body processors
  • Modified XML, JSON, multipart, and URL-encoded parsers to handle partial data when the limit is exceeded
  • Added comprehensive test coverage for partial processing across all supported content types
  • Changed request body limit comparison from >= to > to correctly allow bodies exactly at the limit

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
apache2/apache2_io.c Modified to truncate buffers at limit and enable partial processing mode
apache2/msc_reqbody.c Added function to enable partial processing per processor type
apache2/modsecurity.h Added field and function declaration for partial processing
apache2/msc_json.c Fixed indentation and enabled yajl partial value parsing
apache2/msc_json.h Added function declaration for JSON partial processing
apache2/msc_xml.c Modified to skip well-formed checks when partial processing enabled
apache2/msc_xml.h Added flag to allow ill-formed XML in partial mode
apache2/msc_multipart.c Enhanced boundary handling for partial multipart bodies
apache2/msc_multipart.h Added flag for partial multipart processing
apache2/msc_parsers.c Modified URL-encoded parser to skip final parameter in partial mode
tests/regression/rule/15-json.t Added 6 test cases for JSON partial processing
tests/regression/rule/10-xml.t Added 3 test cases for XML partial processing
tests/regression/config/10-request-directives.t Added extensive multipart, JSON, XML, and URL-encoded partial processing tests

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +355 to 362
if (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT) {
if (rcbe == -5) {
return HTTP_REQUEST_ENTITY_TOO_LARGE;
}
if (rcbe < 0) {
return HTTP_INTERNAL_SERVER_ERROR;
}
}
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error handling logic has been modified to only return error codes when if_limit_action is REQUEST_BODY_LIMIT_ACTION_REJECT. However, this means that when if_limit_action is REQUEST_BODY_LIMIT_ACTION_PARTIAL, errors from modsecurity_request_body_end (rcbe) are silently ignored and APR_SUCCESS is returned. This could mask legitimate parsing errors that occur during partial processing. Consider returning errors for non -5 error codes even in ProcessPartial mode.

Suggested change
if (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT) {
if (rcbe == -5) {
return HTTP_REQUEST_ENTITY_TOO_LARGE;
}
if (rcbe < 0) {
return HTTP_INTERNAL_SERVER_ERROR;
}
}
/* Handle request body processing result:
* - rcbe == -5: body too large -> 413 only in REJECT mode, ignore otherwise.
* - other rcbe < 0: treat as internal error in all modes.
*/
if (rcbe == -5) {
if (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT) {
return HTTP_REQUEST_ENTITY_TOO_LARGE;
}
} else if (rcbe < 0) {
return HTTP_INTERNAL_SERVER_ERROR;
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change causes a parser error returns a response with status code 500, which is not wanted since this case is not an internal server error.
In case of a parse error, REQBODY_ERROR is set to 1, which can be used by a rule to return a 400 Bad Request response, for example:

SecRule REQBODY_ERROR "!@eq 0" "id:'200001', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"

Side note: However, I found that no rule in OWASP CRS 4.22.0 checks REQBODY_ERROR.

This is wanted behavior for both of REQUEST_BODY_LIMIT_ACTION_REJECT and REQUEST_BODY_LIMIT_ACTION_PARTIAL.

Therefore I think the right modification here is:

    if (rcbe == -5 && msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT) {
        return HTTP_REQUEST_ENTITY_TOO_LARGE;
    }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change causes a parser error returns a response with status code 500, which is not wanted since this case is not an internal server error.

okay, then we can make this as resolved. Thanks.

Side note: However, I found that no rule in OWASP CRS 4.22.0 checks REQBODY_ERROR.

This is wanted behavior for both of REQUEST_BODY_LIMIT_ACTION_REJECT and REQUEST_BODY_LIMIT_ACTION_PARTIAL.

Good advice - would you mind to open a PR or just an issue under coreruleset?

Therefore I think the right modification here is:

    if (rcbe == -5 && msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT) {
        return HTTP_REQUEST_ENTITY_TOO_LARGE;
    }

Do you want to add/change this one too? I'm waiting for your response, until that I don't resolve this comment.

SecDebugLogLevel 9
SecRequestBodyAccess On
SecRequestBodyLimitAction ProcessPartial
SecRequestBodyLimit 59
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, please add here and all other tests where you check the limit(s) the SecRequestBodyNoFilesLimit.

I think that would be useful to avoid the unwanted side effects (eg. not the relevant settings applied and a negative test is successed).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before adding tests for SecRequestBodyNoFilesLimit, let me understand it for ProcessPartial.

Though the document for SecRequestBodyNoFilesLimit does not mention for ProcessPartial case, I believe we should not reject a request whose length exceeds the SecRequestBodyNoFilesLimit for ProcessPartial case. Is this correct?

And I found the current implemention is handling the request whose length exceeds SecRequestBodyNoFilesLimit inconsistently between modsecurity_request_body_store and modsecurity_request_body_end.

I fixed it at hnakamur@96a8326.
Could you take a look?

Should I include this commit to this pull request or should I create another pull request for SecRequestBodyNoFilesLimit?

I'll add tests for SecRequestBodyNoFilesLimit after the above fix is settled.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before adding tests for SecRequestBodyNoFilesLimit, let me understand it for ProcessPartial.

Right, thanks.

Though the document for SecRequestBodyNoFilesLimit does not mention for ProcessPartial case, I believe we should not reject a request whose length exceeds the SecRequestBodyNoFilesLimit for ProcessPartial case. Is this correct?

Well, that's a good question.

@dune73 what do you think?

And I found the current implemention is handling the request whose length exceeds SecRequestBodyNoFilesLimit inconsistently between modsecurity_request_body_store and modsecurity_request_body_end.

I fixed it at hnakamur@96a8326. Could you take a look?

Let me take a look at this soon.

Should I include this commit to this pull request or should I create another pull request for SecRequestBodyNoFilesLimit?

It would be great if you merge the current v2/master branch into your working branch. Then after each commit the whole regression test will run, then we can see the tests are passed.

I'll add tests for SecRequestBodyNoFilesLimit after the above fix is settled.

Okay. I'll let you know if I'm done. Thanks.

SecDebugLogLevel 9
SecRequestBodyAccess On
SecRequestBodyLimitAction ProcessPartial
SecRequestBodyLimit 58
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the SecRequestBodyNoFilesLimit too with an exact value.

SecDebugLogLevel 9
SecRequestBodyAccess On
SecRequestBodyLimitAction ProcessPartial
SecRequestBodyLimit 8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the SecRequestBodyNoFilesLimit with an exact value.

In these cases (where you check non-multipart requests) could you add more tests with higher SecRequestBodyLimit values?

@airween
Copy link
Member

airween commented Jan 22, 2026

Hi @hnakamur,

thank you again for your work, I think this is a very important fix.

Please take a look at GH Copilot review, there are a logic change and a typo in the code.

I also added a few notices to tests.

hnakamur and others added 4 commits January 23, 2026 11:31
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@hnakamur hnakamur force-pushed the v2/stop_processing_after_reqbody_limit_for_process_partial branch from 1ea8ee9 to da8b174 Compare January 23, 2026 02:45
@sonarqubecloud
Copy link

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants