Information disclosure

HIGH
victoriametrics/victoriametrics
Commit: 892f4aced235
Affected: 1.139.0 and earlier
2026-06-24 14:38 UTC

Description

The commit implements a security fix by adding a configuration flag http.header.disableServerHostname to disable the X-Server-Hostname header in HTTP responses. Previously, VictoriaMetrics components always included X-Server-Hostname with the server's hostname in responses, which leaks internal host information. This patch mitigates the information disclosure risk by allowing operators to suppress the header. Tests were added to verify the option's behavior. This is a targeted fix for information disclosure via an HTTP response header.

Proof of Concept

PoC (demonstrates information disclosure prior to the fix): 1) Pre-fix behavior (v1.139.0 or earlier): The HTTP response includes X-Server-Hostname with the server's hostname. Example using curl: curl -I http://victoriametrics.example/health HTTP/1.1 200 OK Date: ... X-Server-Hostname: vm-01.internal.example ... 2) Exploitability: Any entity able to access the service can learn the internal hostname of the server from the response headers. This can aid in targeted reconnaissance, social engineering, or internal mapping. 3) Post-fix behavior (with the patch applied): The X-Server-Hostname header can be disabled via the new flag, and will not be present in responses when enabled. Example (with the fix enabled): curl -I http://victoriametrics.example/health HTTP/1.1 200 OK Date: ... ... (No X-Server-Hostname header) 4) Optional verification in code: - Bash (curl): curl -I http://<target>/health | grep -i X-Server-Hostname || true - Python (requests): import requests r = requests.get('http://<target>/health') print('X-Server-Hostname' in r.headers, r.headers.get('X-Server-Hostname'))

Commit Details

Author: Zasda Yusuf Mikail

Date: 2026-06-15 07:05 UTC

Message:

lib/httpserver: allow disabling server hostname header When responding to an HTTP request, VictoriaMetrics components include the X-Server-Hostname. While this may be useful for debugging, it also leaks the hostname. Fixes https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11067

Triage Assessment

Vulnerability Type: Information disclosure

Confidence: HIGH

Reasoning:

The commit introduces a configuration to disable the X-Server-Hostname header in HTTP responses, preventing leakage of the server's hostname. This mitigates information disclosure risk. The tests also validate the option to disable the header.

Verification Assessment

Vulnerability Type: Information disclosure

Confidence: HIGH

Affected Versions: 1.139.0 and earlier

Code Diff

diff --git a/lib/httpserver/httpserver.go b/lib/httpserver/httpserver.go index 19784cb3ae6a5..c0c0d75e79471 100644 --- a/lib/httpserver/httpserver.go +++ b/lib/httpserver/httpserver.go @@ -64,9 +64,10 @@ var ( connTimeout = flag.Duration("http.connTimeout", 2*time.Minute, "Incoming connections to -httpListenAddr are closed after the configured timeout. "+ "This may help evenly spreading load among a cluster of services behind TCP-level load balancer. Zero value disables closing of incoming connections") - headerHSTS = flag.String("http.header.hsts", "", "Value for 'Strict-Transport-Security' header, recommended: 'max-age=31536000; includeSubDomains'") - headerFrameOptions = flag.String("http.header.frameOptions", "", "Value for 'X-Frame-Options' header") - headerCSP = flag.String("http.header.csp", "", `Value for 'Content-Security-Policy' header, recommended: "default-src 'self'"`) + headerHSTS = flag.String("http.header.hsts", "", "Value for 'Strict-Transport-Security' header, recommended: 'max-age=31536000; includeSubDomains'") + headerFrameOptions = flag.String("http.header.frameOptions", "", "Value for 'X-Frame-Options' header") + headerCSP = flag.String("http.header.csp", "", `Value for 'Content-Security-Policy' header, recommended: "default-src 'self'"`) + headerDisableServerHostname = flag.Bool("http.header.disableServerHostname", false, "Whether to disable 'X-Server-Hostname' header in HTTP responses") disableCORS = flag.Bool("http.disableCORS", false, `Disable CORS for all origins (*)`) ) @@ -329,7 +330,9 @@ func handlerWrapper(w http.ResponseWriter, r *http.Request, rh RequestHandler) { if *headerCSP != "" { h.Add("Content-Security-Policy", *headerCSP) } - h.Add("X-Server-Hostname", hostname) + if !*headerDisableServerHostname { + h.Add("X-Server-Hostname", hostname) + } requestsTotal.Inc() if whetherToCloseConn(r) { connTimeoutClosedConns.Inc() diff --git a/lib/httpserver/httpserver_test.go b/lib/httpserver/httpserver_test.go index 474ea44663c15..096778c7c5117 100644 --- a/lib/httpserver/httpserver_test.go +++ b/lib/httpserver/httpserver_test.go @@ -228,4 +228,30 @@ func TestHandlerWrapper(t *testing.T) { if got := h.Get("Content-Security-Policy"); got != cspHeader { t.Fatalf("unexpected CSP header; got %q; want %q", got, cspHeader) } + if got := h.Get("X-Server-Hostname"); got != hostname { + t.Fatalf("unexpected X-Server-Hostname header; got %q; want %q", got, hostname) + } +} + +func TestHandlerWrapperDisableServerHostnameHeader(t *testing.T) { + origDisableServerHostname := *headerDisableServerHostname + *headerDisableServerHostname = true + defer func() { + *headerDisableServerHostname = origDisableServerHostname + }() + + req, _ := http.NewRequest("GET", "/health", nil) + + srv := &server{s: &http.Server{}} + w := &httptest.ResponseRecorder{} + + handlerWrapper(w, req, func(w http.ResponseWriter, r *http.Request) bool { + return builtinRoutesHandler(srv, r, w, func(_ http.ResponseWriter, _ *http.Request) bool { + return true + }) + }) + + if got := w.Header().Get("X-Server-Hostname"); got != "" { + t.Fatalf("unexpected X-Server-Hostname header; got %q; want empty value", got) + } }
← Back to Alerts View on GitHub →