Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 11, 01:00 UTC
fastcgi: take HTTP_HOST from the routed host only (#8355)
Kévin Dunglas committed
Nov 4, 2026 at 20:32 UTC
bd56cc1748caf5fe8bfed6ff0de88ae67c1d0cdb
2 files changed
+28
-1
modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
+6
-1
@@ -437,10 +437,15 @@ func (t Transport) buildEnv(r *http.Request) (envVars, error) {
437
438
// Add all HTTP headers to env variables
439
for field, val := range r.Header {
440
+ switch http.CanonicalHeaderKey(field) {
441
+ // HTTP_HOST comes from r.Host, the host the request was routed on:
442
+ // over HTTP/2, net/http keeps a "host" field distinct from :authority.
443
+ case "Host":
444
+ continue
445
// HTTPoxy mitigation: client-supplied Proxy header must not
446
// be trusted for setting the HTTP_PROXY environment variable.
447
// See https://httpoxy.org for details.
443
- if http.CanonicalHeaderKey(field) == "Proxy" {
448
+ case "Proxy":
449
continue
450
}
451
modules/caddyhttp/reverseproxy/fastcgi/fastcgi_test.go
+22
@@ -487,6 +487,28 @@ func TestBuildEnvDropsProxyHeader(t *testing.T) {
487
})
488
}
489
490
+// Over HTTP/2, net/http keeps a "host" field sent next to :authority in
491
+// r.Header; it must not replace HTTP_HOST, which comes from the routed r.Host.
492
+func TestBuildEnvIgnoresHostHeaderField(t *testing.T) {
493
+ t.Parallel()
494
+
495
+ for _, casing := range []string{"Host", "host"} {
496
+ t.Run("casing "+casing, func(t *testing.T) {
497
+ r := httptest.NewRequest(http.MethodGet, "http://example.com/index.php", nil)
498
+ r.Header = http.Header{casing: []string{"admin.example.com"}}
499
+ ctx := context.WithValue(r.Context(), caddy.ReplacerCtxKey, caddy.NewReplacer())
500
+ ctx = context.WithValue(ctx, caddyhttp.VarsCtxKey, map[string]any{})
501
+ ctx = context.WithValue(ctx, caddyhttp.OriginalRequestCtxKey, *r)
502
+
503
+ env, err := Transport{}.buildEnv(r.WithContext(ctx))
504
+ require.NoError(t, err)
505
+
506
+ assert.Equal(t, "example.com", env["HTTP_HOST"])
507
+ assert.Equal(t, "example.com", env["SERVER_NAME"])
508
+ })
509
+ }
510
+}
511
+
512
// A request path containing dot segments must not let the client select a
513
// different script than the one every path matcher in the chain evaluated.
514
// Matchers judge the cleaned path (see caddyhttp.MatchPath), so the transport