Module

_proxy

Proxy header validation — extract real client info from trusted reverse proxies.

Whentrusted_hostsis configured, X-Forwarded-For/Proto/Host headers are honoured only if the direct peer IP is in the trusted set. When no trusted hosts are configured, forwarded headers are stripped to prevent spoofing.

RFC 7239 defines a formalForwarded header, but the X-Forwarded-* family remains the de-facto standard used by nginx, Caddy, AWS ALB, Cloudflare, and virtually every reverse proxy in production.

Functions

apply_proxy_headers 3 dict[str, Any]
Rewrite ASGI scope fields using proxy headers from a trusted peer. **When the …
def apply_proxy_headers(scope: dict[str, Any], *, trusted_hosts: frozenset[str], trusted_hops: int = 1) -> dict[str, Any]

Rewrite ASGI scope fields using proxy headers from a trusted peer.

When the direct peer is trusted:

  • client is overwritten with the client IP from X-Forwarded-For, selectedtrusted_hopspositions from the RIGHT of the chain so a client-supplied (leftmost) value cannot spoof the perceived client IP
  • scheme is overwritten from X-Forwarded-Proto
  • server host is overwritten from X-Forwarded-Host
  • Host is rewritten from X-Forwarded-Hostfor downstream routing

When the direct peer is not trusted (ortrusted_hostsis empty), allX-Forwarded-*headers are stripped from the scope to prevent downstream apps from trusting spoofed values.

Parameters
Name Type Description
scope dict[str, Any]

Mutable ASGI scope dict (modified in place and returned).

trusted_hosts frozenset[str]

Tuple of trusted peer IPs/hostnames. The wildcard"*"trusts all peers (use only behind a known proxy layer).

trusted_hops int

Number of trusted reverse-proxy hops in front of pounce. The client IP is taken this many positions from the RIGHT ofX-Forwarded-For (each trusted proxy appends the peer it saw), falling back to the direct peer when the chain is shorter. Default 1matches a single trusted proxy.

Default:1
Returns
dict[str, Any]
_select_forwarded_for 2 str
Select the real client IP from an X-Forwarded-For chain by hop count. Each tru…
def _select_forwarded_for(forwarded_for: bytes, trusted_hops: int) -> str

Select the real client IP from an X-Forwarded-For chain by hop count.

Each trusted reverse proxy appends the peer it observed to the right of the chain, so withtrusted_hopstrusted proxies the real client is the entrytrusted_hopspositions from the RIGHT. When the chain is shorter than the configured hop count (e.g. a direct connection, or fewer real proxies than configured), fall back to the leftmost (oldest) entry.

Returns an empty string when no usable address is present.

Parameters
Name Type Description
forwarded_for bytes
trusted_hops int
Returns
str
_split_host_port 2 tuple[str, int]
Split a Host-style value into an ASGI server tuple.
def _split_host_port(host: str, default_port: int) -> tuple[str, int]
Parameters
Name Type Description
host str
default_port int
Returns
tuple[str, int]
_replace_header 3 list[tuple[bytes, bytes]…
Replace the first header named *name*, or append it if missing.
def _replace_header(headers: list[list[bytes]], name: bytes, value: bytes) -> list[tuple[bytes, bytes] | list[bytes]]
Parameters
Name Type Description
headers list[list[bytes]]
name bytes
value bytes
Returns
list[tuple[bytes, bytes] | list[bytes]]
_strip_forwarded_headers 1 None
Remove all X-Forwarded-* headers from an ASGI scope. Prevents untrusted client…
def _strip_forwarded_headers(scope: dict[str, Any]) -> None

Remove all X-Forwarded-* headers from an ASGI scope.

Prevents untrusted clients from injecting proxy headers that downstream ASGI apps might naively trust.

Parameters
Name Type Description
scope dict[str, Any]