Coverage for .venv/lib/python3.13/site-packages/litellm/proxy/middleware/security_headers_middleware.py: 100%
23 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 12:01 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 12:01 +0000
1"""
2Adds anti-framing / content-type security headers to every HTTP response.
4X-Frame-Options and Content-Security-Policy: frame-ancestors 'none' stop the
5admin UI and login pages from being embedded cross-origin (clickjacking).
6X-Content-Type-Options: nosniff stops MIME sniffing.
8Strict-Transport-Security is opt-in via LITELLM_ENABLE_HSTS because it only
9makes sense over HTTPS and would lock browsers out of plain-http deployments.
11Headers are set with setdefault so a route that intentionally sets its own
12value is never overridden.
13"""
15import os
16from typing import Final
18from starlette.datastructures import MutableHeaders
19from starlette.types import ASGIApp, Message, Receive, Scope, Send
21STATIC_SECURITY_HEADERS: Final = (
22 ("X-Frame-Options", "DENY"),
23 ("Content-Security-Policy", "frame-ancestors 'none'"),
24 ("X-Content-Type-Options", "nosniff"),
25)
26HSTS_HEADER: Final = ("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
29def _hsts_enabled() -> bool:
30 return os.getenv("LITELLM_ENABLE_HSTS", "false").strip().lower() == "true"
33class SecurityHeadersMiddleware:
34 def __init__(self, app: ASGIApp) -> None:
35 self.app = app
37 async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
38 if scope["type"] != "http":
39 await self.app(scope, receive, send)
40 return
42 async def send_with_security_headers(message: Message) -> None:
43 if message["type"] == "http.response.start":
44 headers: Final = MutableHeaders(scope=message)
45 applied: Final = (*STATIC_SECURITY_HEADERS, HSTS_HEADER) if _hsts_enabled() else STATIC_SECURITY_HEADERS
46 for name, value in applied:
47 headers.setdefault(name, value)
48 await send(message)
50 await self.app(scope, receive, send_with_security_headers)