owasp-modsecurity / owasp-modsecurity/ModSecurity
Duplicate Server headers in Audit Log when using more_set_headers or more_clear_headers in Nginx
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 9.8k
- Forks
- 1.8k
- Avg merge
- 2h 46m
- Merged PRs (30d)
- 1
Description
Describe the bug
Hi, the Audit Log duplicates the Server header content under the Response headers section F.
When configuring Nginx with the following directives, the Audit Log duplicates the Server header as shown.
Options that trigger the issue:
more_clear_headers Server;more_set_headers 'Server: Custom Name';
First case (more_set_headers 'Server: Custom Name';)
Nginx configuration:
# Other options...
keepalive_timeout 15;
send_timeout 10;
more_set_headers 'Server: Custom Name'; # This option causes the duplicate response header.
proxy_hide_header X-Powered-By;
# Other options...
Logs and dumps: Audit Log
---Bo5kPrA4---A--
[30/Apr/2025:03:37:24 -0600] 174600584494.932607 192.168.1.35 41310 192.168.1.35 80
---Bo5kPrA4---B--
GET /?foo=/etc/passwd&bar=/bin/sh HTTP/1.1
Host: domain.host.sh
User-Agent: curl/8.5.0
Accept: */*
---Bo5kPrA4---D--
---Bo5kPrA4---E--
<html>\x0d\x0a<head><title>403 Forbidden</title></head>\x0d\x0a<body>\x0d\x0a<center><h1>403 Forbidden</h1></center>\x0d\x0a<hr><center>nginx</center>\x0d\x0a</body>\x0d\x0a</html>\x0d\x0a
---Bo5kPrA4---F--
HTTP/1.1 403
Server: Custom Name # Duplicate header.
Server: Custom Name # Duplicate header.
Date: Wed, 30 Apr 2025 09:37:24 GMT
Content-Length: 146
Content-Type: text/html
Connection: keep-alive
Second case (more_clear_headers Server;)
Nginx configuration:
# Other options...
keepalive_timeout 15;
send_timeout 10;
more_clear_headers Server; # This option causes the duplicate response header.
proxy_hide_header X-Powered-By;
# Other options...
Logs and dumps: Audit Log
---71j15QKX---A--
[30/Apr/2025:03:25:40 -0600] 174600514087.352175 192.168.1.35 39024 192.168.1.35 80
---71j15QKX---B--
GET /?foo=/etc/passwd&bar=/bin/sh HTTP/1.1
Host: domain.host.sh
User-Agent: curl/8.5.0
Accept: */*
---71j15QKX---D--
---71j15QKX---E--
<html>\x0d\x0a<head><title>403 Forbidden</title></head>\x0d\x0a<body>\x0d\x0a<center><h1>403 Forbidden</h1></center>\x0d\x0a<hr><center>nginx</center>\x0d\x0a</body>\x0d\x0a</html>\x0d\x0a
---71j15QKX---F--
HTTP/1.1 403
Server: # Duplicate header.
Server: # Duplicate header.
Date: Wed, 30 Apr 2025 09:25:40 GMT
Content-Length: 146
Content-Type: text/html
Connection: keep-alive
Final case (baseline without header modification)
Nginx configuration:
# Other options...
keepalive_timeout 15;
send_timeout 10;
# Other options...
Logs and dumps: Audit Log
---qfTAvG5v---A--
[30/Apr/2025:03:30:38 -0600] 174600543867.582044 192.168.1.35 36722 192.168.1.35 80
---qfTAvG5v---B--
GET /?foo=/etc/passwd&bar=/bin/sh HTTP/1.1
Host: domain.host.sh
User-Agent: curl/8.5.0
Accept: */*
---qfTAvG5v---D--
---qfTAvG5v---E--
<html>\x0d\x0a<head><title>403 Forbidden</title></head>\x0d\x0a<body>\x0d\x0a<center><h1>403 Forbidden</h1></center>\x0d\x0a<hr><center>nginx</center>\x0d\x0a</body>\x0d\x0a</html>\x0d\x0a
---qfTAvG5v---F--
HTTP/1.1 403
Server: nginx # Correct.
Date: Wed, 30 Apr 2025 09:30:38 GMT
Content-Length: 146
Content-Type: text/html
Connection: keep-alive
To Reproduce
Steps to reproduce the behavior:
-
Configure the
nginx.conffile using either:more_clear_headers Server;more_set_headers 'Server: Custom Name';
Each directive was tested separately (never together).
-
Test the configuration:
nginx -t -
Reload Nginx:
nginx -s reload -
Send a request to trigger the rule:
curl 'http://domain.host.sh/?foo=/etc/passwd&bar=/bin/sh'
Expected behavior
The expected behavior is that ModSecurity's Audit Log should not duplicate the Server response header when using either more_clear_headers Server; or more_set_headers 'Server: Custom Name';.
Server (please complete the following information):
- ModSecurity v3.0.14 with nginx-connector v1.0.3
- WebServer: nginx/1.28.0
- OS: Ubuntu 24.04.2 LTS
Rule Set (please complete the following information):
- OWASP CRS v4.13.0
Additional context
After successfully compiling ModSecurity v3.0.14 with:
./configure --with-pcre2
I created the following directory structure:
/usr/local/modsecurity/etc
/usr/local/modsecurity/var
/usr/local/modsecurity/var/audit
/usr/local/modsecurity/var/data
/usr/local/modsecurity/var/log
/usr/local/modsecurity/var/tmp
/usr/local/modsecurity/var/upload
I then assigned appropriate ownership and permissions to each directory.
Following that, I applied the following configuration to ModSecurity:
SecRuleEngine On
SecPcreMatchLimit 150000
SecPcreMatchLimitRecursion 150000
SecResponseBodyAccess Off
SecTmpDir /usr/local/modsecurity/var/tmp/
SecDataDir /usr/local/modsecurity/var/data/
SecUploadDir /usr/local/modsecurity/var/upload/
SecUploadKeepFiles Off
SecUploadFileMode 0600
SecDebugLog /usr/local/modsecurity/var/log/debug.log
SecDebugLogLevel 3
SecAuditLog /usr/local/modsecurity/var/log/audit.log
SecAuditLogStorageDir /usr/local/modsecurity/var/audit/
I then compiled ModSecurity-nginx v1.0.3 with:
./configure --with-compat --with-http_ssl_module --add-dynamic-module=../modsecurity-nginx-v1.0.3
After several additional steps to load the necessary libraries, configure settings, and complete the setup, I installed the latest version of the OWASP Core Rule Set (CRS).
While testing the configuration and writing custom rules for my application, I noticed an issue when inspecting the Audit Logs. Specifically, when experimenting with Response headers in Nginx, I observed the Server header being duplicated.
I understand that not all of this information may be essential, but I wanted to provide as much detail as possible. I hope this helps clarify the context of the issue.
Thanks!
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the nginx.conf configurations using more_set_headers or more_clear_headers, then reproduce with nginx -t, nginx -s reload, and the supplied curl request. Trace the response-header audit logging path for the F section; done means each configuration records the Server header once, matching the baseline audit log.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, nginx
- Domain
- security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100