Skip to content

fix: record real response status for IIS audit log F part - #3613

Open
A13501350 wants to merge 5 commits into
owasp-modsecurity:v2/masterfrom
A13501350:pr/iis-audit-log-fpart-status
Open

fix: record real response status for IIS audit log F part#3613
A13501350 wants to merge 5 commits into
owasp-modsecurity:v2/masterfrom
A13501350:pr/iis-audit-log-fpart-status

Conversation

@A13501350

@A13501350 A13501350 commented Aug 14, 2026

Copy link
Copy Markdown

Summary

Fixes the IIS connector so the audit log's F part records the real HTTP response status instead of a bogus 500 Internal Server Error.

Problem

In the IIS connector, r->status was never populated from the actual HTTP response. request_rec is apr_pcalloc'd, so r->status stayed 0. When the logging hook builds the F part it calls ap_get_status_line(r->status); for r->status == 0 the standalone ap_index_of_response() maps any value < 100 to LEVEL_500, so every transaction logged HTTP/1.1 500 Internal Server Error regardless of the true response code.

--F--
HTTP/1.1 500 Internal Server Error   <- wrong, e.g. actual response is 200 OK

There was a second, related source of bogus 500 records: the IIS default-document rewrite (e.g. GET / internally redirected to /iisstart.htm) supersedes the original request before it ever reaches OnSendResponse, so its r->status stays 0 and hook_log_transaction wrote a phantom 500 record for it.

Fix

  1. In CMyHttpModule::OnSendResponse (iis/mymodule.cpp), transfer the raw response status into r->status (and build r->status_line from the reason phrase) before the rest of the response handling:
if(pRawHttpResponse->StatusCode > 0)
{
    r->status = pRawHttpResponse->StatusCode;

    if(pRawHttpResponse->pReason != NULL && pRawHttpResponse->ReasonLength > 0)
    {
        r->status_line = apr_psprintf(r->pool, "%d %s", r->status,
            ZeroTerminate(pRawHttpResponse->pReason, pRawHttpResponse->ReasonLength, r->pool));
    }
}
  1. In hook_log_transaction (apache2/mod_security2.c, under VERSION_IIS), skip audit logging for transactions that never received a response status and were not intercepted. In the IIS connector r->status is only ever set by OnSendResponse, so r->status == 0 && !msr->was_intercepted uniquely identifies requests superseded by an internal redirect:
#if defined(VERSION_IIS)
    if (r->status == 0 && msr->was_intercepted == 0) {
        return DECLINED;
    }
#endif

A blocked request always reaches OnSendResponse with r->status set (e.g. 403), so intercepted transactions are unaffected.

Verification

Verified against a local IIS default site with OWASP CRS (and in the module's Windows CI, which enables the audit log and asserts the F-part status lines):

  • Normal GET / now logs HTTP/1.1 200 OK (single record; the phantom 500 records for the internal redirect are gone)
  • Blocked request (SQLi/XSS) logs HTTP/1.1 403 ModSecurity Action

Closes #3612

The IIS connector never copied the HTTP response status into the
request_rec, so r->status stayed 0 and the audit log rendered the F part
as a bogus 'HTTP/1.1 500 Internal Server Error' (ap_get_status_line(0))
for every transaction.

Set r->status and r->status_line from the raw HTTP_RESPONSE in
OnSendResponse so the logging hook and relevant-status checks use the
real response code.
@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ae64ab1b-d54d-44e9-92e3-8fc249c58da3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@airween

airween commented Aug 14, 2026

Copy link
Copy Markdown
Member

Hi @A13501350,

thanks for the fix (and the report too) - could you add some tests to the CI to check this expected behavior? (Not just for this case, but I assume this is important in the future, so if anyone makes some changes, we should be sure the behavior is the same...)

@airween airween added Platform - IIS 2.x Related to ModSecurity version 2.x labels Aug 14, 2026
The IIS connector never copies the response status into the request_rec;
r->status is only set in OnSendResponse. A request superseded by an
internal redirect (e.g. the IIS default document rewrite of "/" to
"/iisstart.htm") never reaches OnSendResponse, so its r->status stays 0
and the audit log F part would record a bogus HTTP/1.1 500 Internal
Server Error (ap_get_status_line(0)).

Skip audit logging for such transactions unless they were actually
intercepted. A blocked request always reaches OnSendResponse with
r->status set (403), so it is unaffected.
@A13501350

A13501350 commented Aug 15, 2026

Copy link
Copy Markdown
Author

I can add tests for this. That said, the current workflow is mainly set up to verify that the build compiles and runs. It would be cleaner to test in a dedicated action. Regarding the SonarCloud Quality Gate failure, I'd prefer to keep the original code structure, so I am unable to refactor those lines to meet the maintainability rating.

@airween

airween commented Aug 15, 2026

Copy link
Copy Markdown
Member

I can add tests for this. That said, the current workflow is mainly set up to verify that the build compiles and runs. It would be cleaner to test in a dedicated action. Regarding the SonarCloud Quality Gate failure, I'd prefer to keep the original code structure, so I am unable to refactor those lines to meet the maintainability rating.

Feel free to add a test case, based on Linux tests. (But the regression tests there use Apache, so probably that won't be good to you. This part probably more useful for first time.)

Replace the go-ftw cloud-mode run with file-based audit logging and a
config-driven smoke suite.

- iis/tests/ftw.yaml: go-ftw config. include selects a representative
  subset of rule families (913/920/930/941); testoverride.ignore lists
  tests that cannot pass on IIS/HTTP.SYS (behavior differences, not
  module faults).
- iis/tests/crs-900005.conf: CRS regression-suite config (rule 900005),
  appended to crs-setup.conf before the rule files.
- iis/tests/audit-logging.conf: file-based audit log + go-ftw marker.
- iis/tests/web.config: IIS reverse proxy to the albedo backend.
- workflow: download CRS, assemble config, deploy web.config, run
  go-ftw, upload the audit log as an artifact.
Comment thread iis/tests/web.config
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

web.config exists solely for the CI test environment and never serves real traffic, so I'd consider this ignorable.

@A13501350
A13501350 force-pushed the pr/iis-audit-log-fpart-status branch from 2c6e8c3 to 166ed5e Compare August 15, 2026 15:14
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
B Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@A13501350

A13501350 commented Aug 18, 2026

Copy link
Copy Markdown
Author

For this specific case I've already added a test. Regarding a full regression suite, since IIS/HTTP.SYS behaves differently from Apache like you said, running the complete CRS suite is quite painful. I only cherry-pick a few tests in CI.

Comment thread iis/mymodule.cpp

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Like I said before, legacy code is usually not convenient to refactor.

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

Labels

2.x Related to ModSecurity version 2.x Platform - IIS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants