@marcel91200 / caddy Mirror · read-only / commits / 70dca34a
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: let configured env variables override request headers (#8358)

Kévin Dunglas committed Nov 5, 2026 at 00:02 UTC 70dca34a36de12977673189b4789d45cfa81aaa5
2 files changed +31 -5
modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
+7 -5
@@ -437,11 +437,6 @@ func (t Transport) buildEnv(r *http.Request) (envVars, error) {
437 }
438 }
439
440 - // Add env variables from config (with support for placeholders in values)
441 - for key, value := range t.EnvVars {
442 - env[key] = repl.ReplaceAll(value, "")
443 - }
444 -
440 // Add all HTTP headers to env variables
441 for field, val := range r.Header {
442 switch http.CanonicalHeaderKey(field) {
@@ -460,6 +455,13 @@ func (t Transport) buildEnv(r *http.Request) (envVars, error) {
455 header = headerNameReplacer.Replace(header)
456 env["HTTP_"+header] = strings.Join(val, ", ")
457 }
458 +
459 + // Add env variables from config (with support for placeholders in values)
460 + // last, so a client header cannot override an HTTP_* variable set by the operator
461 + for key, value := range t.EnvVars {
462 + env[key] = repl.ReplaceAll(value, "")
463 + }
464 +
465 return env, nil
466 }
467
modules/caddyhttp/reverseproxy/fastcgi/fastcgi_test.go
+24
@@ -509,6 +509,30 @@ func TestBuildEnvIgnoresHostHeaderField(t *testing.T) {
509 }
510 }
511
512 +// A client header must not override an HTTP_* variable set with the env subdirective.
513 +func TestBuildEnvConfiguredVarsOverrideHeaders(t *testing.T) {
514 + t.Parallel()
515 +
516 + r := httptest.NewRequest(http.MethodGet, "http://example.com/index.php", nil)
517 + r.Header.Set("X-Forwarded-Proto", "http")
518 + r.Header.Set("X-Auth-User", "admin")
519 + repl := caddy.NewReplacer()
520 + repl.Set("http.auth.user.id", "alice")
521 + ctx := context.WithValue(r.Context(), caddy.ReplacerCtxKey, repl)
522 + ctx = context.WithValue(ctx, caddyhttp.VarsCtxKey, map[string]any{})
523 + ctx = context.WithValue(ctx, caddyhttp.OriginalRequestCtxKey, *r)
524 +
525 + tr := Transport{EnvVars: map[string]string{
526 + "HTTP_X_FORWARDED_PROTO": "https",
527 + "HTTP_X_AUTH_USER": "{http.auth.user.id}",
528 + }}
529 + env, err := tr.buildEnv(r.WithContext(ctx))
530 + require.NoError(t, err)
531 +
532 + assert.Equal(t, "https", env["HTTP_X_FORWARDED_PROTO"])
533 + assert.Equal(t, "alice", env["HTTP_X_AUTH_USER"])
534 +}
535 +
536 // A request path containing dot segments must not let the client select a
537 // different script than the one every path matcher in the chain evaluated.
538 // Matchers judge the cleaned path (see caddyhttp.MatchPath), so the transport