Prevent Host Header Poisoning in URLs
mainUsing Request.url_for(...) derives the scheme and host from the incoming Host header. If your application does not validate this header, attackers can poison absolute URLs (including hx-get, hx-post, and redirects) to point to malicious domains.
Best Practices:
- Use Relative Paths: Prefer
request.url_path_for(...)orrequest.url_for(...).pathfor in-app links and htmx attributes. These cannot be poisoned. - Use Trusted Hosts: Use
starlette.middleware.trustedhost.TrustedHostMiddlewareto reject requests with forgedHostheaders. - Use Trusted Proxies: If behind a CDN/Proxy, use
ProxyHeadersMiddlewareto ensureX-Forwarded-*headers are only honored from trusted IP ranges. - Avoid Request-derived Absolute URLs: For outbound links (emails, OAuth), use a configuration-controlled
BASE_URLinstead of deriving it from the request.
# GOOD: Relative path, cannot be poisoned
a("Profile", href=request.url_path_for("profile", user_id=user.id))
button(
"Refresh",
hx_get=request.url_path_for("items_partial"),
hx_target="#items",
)
# BAD: Host comes from the request and can be poisoned
a("Profile", href=str(request.url_for("profile", user_id=user.id)))