@marcel91200 / caddy Mirror · read-only / commits / bd56cc17
Fork 0

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