Remediation Guides

How to Fix Web Server HTTP Header Internal IP Disclosure (Nessus 10759) on IIS, Apache and nginx

26 September 2026 8 min read

Web Server HTTP Header Internal IP Disclosure means a web server writes its private (RFC 1918) address into a response header, usually Location or Content-Location, typically when a client sends a request with no Host header. On IIS 7 and later, fix it by setting alternateHostName in system.webServer/serverRuntime to your public host name, then rescan.

What the scanner is actually detecting

Whenever a web server has to build an absolute URL about itself, for example a courtesy redirect from /images to /images/, it needs a host name. Normally it copies the client’s Host header. HTTP/1.1 makes that header mandatory, but an HTTP/1.0 request can leave it out, and many servers then fall back to the IP address the connection arrived on. Behind NAT or a load balancer, that is a private address the outside world was never meant to see.

Three common checks report this, but not in the same place:

Scanner and ID Finding title Where it looks Severity
Nessus plugin 10759 Web Server HTTP Header Internal IP Disclosure HTTP response headers Low (CVSS v3 base 3.1)
Tenable WAS plugin 98077 Private IP Address Disclosure HTML response body Info
ZAP alert 2 (passive) Private IP Disclosure HTTP response body Low, CWE-497

Tenable’s description of plugin 10759 names Microsoft IIS 4.0 as the original default-configuration culprit (the plugin maps to CVE-2000-0649), and notes that other web servers, applications, proxies and load balancers can leak the same way through redirect misconfiguration. Its published solution is only “Apply configuration suggested by vendor”, which is what the rest of this guide spells out. ZAP’s rule also flags Amazon EC2 private host names such as ip-10-0-56-78.

In practice, a Nessus 10759 hit is a server or proxy configuration fix, while WAS 98077 and ZAP hits usually mean application content to edit.

Real-world risk

This is a low-severity reconnaissance finding. Nobody gains access from it. It reveals a piece of your internal addressing: the subnet a web tier lives in and, behind a load balancer, often one address per node. That can help with later steps such as aiming a server-side request forgery bug at internal ranges. Fix it because the change is small and it keeps reappearing in external scans and pentest reports, not because it is urgent.

How to confirm it on the host

Reproduce what the scanner does: send an HTTP/1.0 request with no Host header. With curl, -H “Host:” removes the Host header curl would normally add, and –http1.0 sets the protocol version. Request the root, an existing folder without its trailing slash, and the HTTPS listener:

curl -si --http1.0 -H "Host:" http://203.0.113.10/
curl -si --http1.0 -H "Host:" http://203.0.113.10/images
curl -sik --http1.0 -H "Host:" https://203.0.113.10/

On Windows, call curl.exe explicitly, because Windows PowerShell treats plain curl as an alias for Invoke-WebRequest. A raw request works too:

printf 'GET / HTTP/1.0rnrn' | nc 203.0.113.10 80
printf 'GET / HTTP/1.0rnrn' | openssl s_client -quiet -connect 203.0.113.10:443

Look at Location and Content-Location. If either contains a 10.x, 172.16 to 172.31, or 192.168 address, you have reproduced the finding. Test through the public address or load balancer VIP and also against each backend node directly, because nodes are often configured differently.

On an IIS server, check whether a name is already configured and which site answers requests without a Host header:

%windir%system32inetsrvappcmd.exe list config -section:system.webServer/serverRuntime
%windir%system32inetsrvappcmd.exe list site

If alternateHostName does not appear in the first output, it is not set. In the site list, a binding with nothing after the last colon (for example http/*:80:) has no host name, so that site is the one receiving Host-less requests.

How to fix it

IIS 7.0 through IIS 10

Microsoft’s serverRuntime reference describes alternateHostName as the host name IIS uses for redirection and in the Content-Location header instead of the computer name. There is no dedicated IIS Manager page for this element, so set it with appcmd. Take a configuration backup first:

%windir%system32inetsrvappcmd.exe add backup "before-alternateHostName"
%windir%system32inetsrvappcmd.exe set config -section:system.webServer/serverRuntime /alternateHostName:"www.example.com" /commit:apphost

That applies server-wide. On a server hosting several sites, scope it to the site with the blank host-name binding, since only that site can receive requests without a Host header:

%windir%system32inetsrvappcmd.exe set config "Default Web Site" -section:system.webServer/serverRuntime /alternateHostName:"www.example.com" /commit:apphost

Microsoft notes that /commit:apphost is required for this section, so the value lands in a location block in applicationHost.config. Use the public name users actually type, not the machine name.

If IIS still leaks the address

Microsoft documents one known gap: an ISAPI filter that reads SERVER_NAME during the SF_NOTIFY_PREPROC_HEADERS notification runs before IIS reads alternateHostName, so it can only return the IP (a hotfix exists for IIS 7.0). A Microsoft support engineer traced the same symptom on IIS 6 to a third-party wildcard ISAPI connector. List the filters in use:

%windir%system32inetsrvappcmd.exe list config -section:system.webServer/isapiFilters

Also check application code that builds absolute URLs from the SERVER_NAME or LOCAL_ADDR server variables, and switch it to a configured public base URL. On IIS 6.0 the equivalent was the SetHostName metabase property, but IIS 6.0 is long out of support.

Apache httpd

With the default UseCanonicalName Off, Apache uses the client’s host name when one is supplied and otherwise falls back to ServerName. If ServerName is not set, httpd guesses from the system host name or a reverse lookup, which is how internal names and addresses escape. Set it explicitly in the main config and in every VirtualHost, including the default one. Behind a TLS-offloading load balancer, the Apache documentation recommends including the scheme and port:

ServerName https://www.example.com:443

When Apache is the reverse proxy, ProxyPassReverse rewrites the Location, Content-Location and URI headers that backends send on redirects. It does not rewrite URLs inside HTML.

ProxyPass        "/" "http://10.0.0.21:8080/"
ProxyPassReverse "/" "http://10.0.0.21:8080/"

Validate with apachectl configtest, then reload.

nginx

The nginx documentation is explicit: with the default server_name_in_redirect off, nginx uses the Host header in absolute redirects and, if it is missing, the server’s IP address. Either send relative redirects (nginx 1.11.8 and later) or force the primary server name:

server {
    listen 80 default_server;
    server_name www.example.com;
    absolute_redirect off;
    # alternative: server_name_in_redirect on;
}

As a reverse proxy, pass a real host name to the backend and rewrite backend redirects. The $host variable falls back to the matching server name when the client sent no Host header. Note that proxy_redirect changes the Location and Refresh headers only, not Content-Location.

location / {
    proxy_pass       http://10.0.0.21:8080;
    proxy_set_header Host $host;
    proxy_redirect   http://10.0.0.21:8080/ /;
}

Run nginx -t, then reload.

Load balancers and application content

If a hardware or cloud load balancer passes backend headers through untouched, fix each backend as above, use the vendor’s documented response-header rewrite for Location and Content-Location, or reject requests without a Host header at the edge. For WAS 98077 and ZAP body findings, remove private addresses from HTML and JavaScript comments, embedded configuration, error pages and debug output; ZAP recommends server-side comments, which never reach the browser.

How to verify the fix and rescan

  1. Repeat the curl tests against the VIP and every node. Location should now show the public name or a relative path:
    curl -si --http1.0 -H "Host:" http://203.0.113.10/images | grep -Ei "^(location|content-location):"
  2. For body findings, grep the pages the scanner reported for private ranges:
    curl -s https://www.example.com/ | grep -Eo 'b(10.[0-9]{1,3}.[0-9]{1,3}|172.(1[6-9]|2[0-9]|3[01]).[0-9]{1,3}|192.168.[0-9]{1,3}).[0-9]{1,3}b'
  3. Rescan with the tool that raised the finding. For Nessus, scan the same target with a policy that includes plugin 10759. ZAP alert 2 is passive, so any fresh crawl through ZAP re-evaluates it. For Tenable WAS, run a new scan of the same application.

What can break and how to roll back

  • Browsers always send Host, so users are not affected. Health checks or monitoring probes that send HTTP/1.0 without Host and follow redirects will now go to the public name, which may not resolve from the management network.
  • On a multi-site IIS server, a wrong alternateHostName sends Host-less clients to the wrong site.
  • Apache: omitting the https:// scheme in ServerName behind TLS offload can produce http:// redirects, and switching to UseCanonicalName On forces the canonical name even for users who arrive via another name.
  • nginx: absolute_redirect off produces relative Location values, which HTTP permits (RFC 9110, section 10.2.2), but check any client that assumes absolute URLs.

To roll back IIS, restore the backup. This restores the whole configuration snapshot, so any other change made after the backup is lost too; alternatively, delete the alternateHostName attribute from %windir%system32inetsrvconfigapplicationHost.config.

%windir%system32inetsrvappcmd.exe restore backup "before-alternateHostName"

On Apache or nginx, revert the directive, run the config test and reload.

Common false positive reasons

  • Internal scan, internal target. If the scanner reached the host at 10.0.0.21 and the header says 10.0.0.21, nothing new was disclosed. Before closing it that way, confirm the host is not also published through NAT, where the same behavior would leak.
  • The address belongs to another layer. The IP may be the proxy or load balancer, so fixing the web server alone will not clear it.
  • Look-alike numbers in the body. Body checks match patterns, so a version string, build number or sample value in a private range can trigger them. Tenable itself recommends manually verifying the context for 98077.
  • Stale results. The finding predates the change, or a CDN served a cached page.

These overlap with the real causes of vulnerability scanner false positives.

FAQ

Is this finding exploitable on its own?

No. It discloses an internal address and nothing else. Treat it as low priority hygiene, and fix it in a normal change window.

Why do I never see the internal IP in a browser?

Browsers send a Host header on every request, so the server uses that name. Scanners deliberately send HTTP/1.0 requests without Host to trigger the fallback.

Can I fix it at the WAF instead of on every server?

Often yes, by rejecting Host-less requests or rewriting headers at the edge. Keep in mind that a WAF also changes what scanners see, as explained in how a WAF changes what your web scanner reports, so rescan from outside after the change.

Tracking this finding across many hosts

Behind a load balancer this finding tends to appear once per node and again from each scanner that looked, so it is easy to lose track of which backends are actually fixed. SITEY, a self-hosted vulnerability management platform, imports findings from 16 scanners, merges duplicates within each scanner, and can retest individual Nessus findings such as plugin 10759 after the change. Host-specific remediation scripts it drafts run through SITEY agents on Windows and Linux only after human approval.

Sources

SITEY closes the loop, not just the report.Discover, validate, fix and verify in your own infrastructure.

See pricing