Skip to content

fix: don't trust forwarded headers from arbitrary clients#62

Merged
andregoepel merged 2 commits into
mainfrom
bugfix/forwarded-headers-trust
Jul 4, 2026
Merged

fix: don't trust forwarded headers from arbitrary clients#62
andregoepel merged 2 commits into
mainfrom
bugfix/forwarded-headers-trust

Conversation

@andregoepel

Copy link
Copy Markdown
Owner

Closes #51 (F2 — forwarded headers trusted from all proxies).

What

UseAppFoundation previously did KnownIPNetworks.Clear() + KnownProxies.Clear() unconditionally, so X-Forwarded-For / X-Forwarded-Proto were honored from any caller. This makes forwarded-header trust configurable and secure by default:

  • AppFoundationOptions.KnownProxyNetworks (CIDRs) and KnownProxies (IPs) — declare the reverse proxies whose headers are trusted. When either is set, only those origins are trusted (framework loopback defaults are cleared).
  • No proxies configured: trust every origin in Development (local convenience), but only loopback otherwise — so arbitrary clients can't spoof the client IP/scheme in production. A one-time warning is logged in non-Development so operators behind a proxy know to configure it.
  • ConfigureForwardedHeaders hook for full control (ForwardLimit, or deliberately trusting all when an upstream ingress sanitizes the headers).

The trust-building logic is extracted to an internal BuildForwardedHeadersOptions(options, isDevelopment) helper and unit-tested.

Why

With the lists cleared, a client could send X-Forwarded-For: 1.2.3.4 to forge RemoteIpAddress (falsifying audit logs, bypassing any IP allowlist/rate limit) or X-Forwarded-Proto: https to confuse scheme-dependent logic. As a reusable foundation, "trust all proxies" is an unsafe default to ship to every consumer.

⚠️ Upgrade note (behavior change)

Hosts running in a non-Development environment behind a reverse proxy must now set KnownProxyNetworks/KnownProxies (or use ConfigureForwardedHeaders) to keep seeing the real client IP/scheme — otherwise forwarded headers are honored only from loopback. The logged warning points this out. A host that truly wants the old behavior can clear the lists via ConfigureForwardedHeaders.

builder.AddAppFoundation(o =>
{
    o.KnownProxyNetworks.Add("10.0.0.0/8"); // your ingress/proxy subnet
});

Tests

ForwardedHeadersOptionsTests covers: forwarded flags always set; non-Dev + no proxies keeps loopback-only (not wide open); Dev + no proxies trusts all; configured proxies trusted exactly (defaults cleared).

Verification

UseAppFoundation cleared KnownIPNetworks and KnownProxies unconditionally,
so the app honored X-Forwarded-For / -Proto from any caller. Without a
trusted proxy always overwriting those headers, a client could spoof its
source IP (falsifying audit logs, bypassing IP-based controls) or the
request scheme.

Make forwarded-header trust configurable and secure by default:
- New AppFoundationOptions.KnownProxyNetworks / KnownProxies let a host
  declare the reverse-proxy CIDRs / IPs whose headers are trusted; when
  set, only those origins are trusted.
- With none configured, trust every origin in Development (local
  convenience) but only loopback otherwise, and log a warning in non-Dev
  so operators behind a proxy know to configure it.
- New ConfigureForwardedHeaders hook for full control (e.g. ForwardLimit,
  or deliberately trusting all when an ingress sanitizes the headers).

Closes #51
Production proxy CIDRs are typically unknown at build time, so allow the
KnownProxyNetworks / KnownProxies trust lists to be supplied via
configuration (AppFoundation:KnownProxyNetworks / :KnownProxies) in
addition to code — as a delimited scalar (friendly for a single env var
or .env entry) or a configuration array. Config values augment and
de-duplicate against anything set in the configure callback. IPv6 CIDRs
are preserved (split never uses ':').
@andregoepel
andregoepel merged commit ba97578 into main Jul 4, 2026
3 checks passed
@andregoepel
andregoepel deleted the bugfix/forwarded-headers-trust branch July 5, 2026 07:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security] Forwarded headers trusted from all proxies — IP/scheme spoofing (F2)

1 participant