IIS: Content-Length header corrupted/truncated for large responses (wrong printf format + off-by-one buffer size)

Author: A13501350Created Aug 27, 2026Updated Sep 15, 2026
LabelsPlatform - IIS2.x

Summary

In iis/mymodule.cpp, StringCchPrintfA is used to build the Content-Length header value, but it has two defects that corrupt the header for large responses:

  1. Wrong format specifier for 64-bit value. At the response path, ulTotalLength is a ULONGLONG, but it is printed with "%d" (which expects a 32-bit int). printf only reads the low 32 bits, so the resulting Content-Length is wrong whenever the response body exceeds ~2 GiB. The other two call sites format an unsigned int length with "%d" as well (should be %u).
  2. Off-by-one destination size. StringCchPrintfA's cchDest argument is passed as sizeof(szLength)/sizeof(CHAR) - 1 (= 20). Since this argument must include the null terminator, the buffer can only hold 19 digits. A 64-bit value can be 20 decimal digits (e.g. 18446744073709551615), so it is silently truncated / the call fails.

Impact

When ModSecurity for IIS must synthesize the Content-Length header (the only-response, non-chunked case), a wrong value causes clients to hang or error because the body length does not match the advertised header.

Affected locations (v2/master)

  • iis/mymodule.cpp:642ulTotalLength (ULONGLONG) -> "%llu"
  • iis/mymodule.cpp:1140length (unsigned int) -> "%u"
  • iis/mymodule.cpp:1228length (unsigned int) -> "%u"

All three should also pass the full buffer size sizeof(szLength)/sizeof(CHAR) (21) instead of ... - 1.

Suggested fix

c
CHAR szLength[21]; // Max length for a 64-bit int is 20 digits + null
ZeroMemory(szLength, sizeof(szLength));

HRESULT hr = StringCchPrintfA(
    szLength,
    sizeof(szLength) / sizeof(CHAR), // includes null terminator
    "%llu",                          // ULONGLONG
    ulTotalLength);

Source: owasp-modsecurity/ModSecurity