From 58db8be1173fd8369f44659c76d067d155e52241 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Wed, 25 Feb 2026 03:39:49 +0530 Subject: [PATCH] fix(security): update security header names to lowercase and add tests --- backend/app/core/security_headers.py | 8 +++--- .../tests/test_security_headers_middleware.py | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/backend/app/core/security_headers.py b/backend/app/core/security_headers.py index 3aa3a78e..758c36b4 100644 --- a/backend/app/core/security_headers.py +++ b/backend/app/core/security_headers.py @@ -11,10 +11,10 @@ if TYPE_CHECKING: # pragma: no cover class SecurityHeadersMiddleware: """Inject configured security headers into every HTTP response.""" - _X_CONTENT_TYPE_OPTIONS = b"X-Content-Type-Options" - _X_FRAME_OPTIONS = b"X-Frame-Options" - _REFERRER_POLICY = b"Referrer-Policy" - _PERMISSIONS_POLICY = b"Permissions-Policy" + _X_CONTENT_TYPE_OPTIONS = b"x-content-type-options" + _X_FRAME_OPTIONS = b"x-frame-options" + _REFERRER_POLICY = b"referrer-policy" + _PERMISSIONS_POLICY = b"permissions-policy" def __init__( self, diff --git a/backend/tests/test_security_headers_middleware.py b/backend/tests/test_security_headers_middleware.py index 978b6c19..844aeccf 100644 --- a/backend/tests/test_security_headers_middleware.py +++ b/backend/tests/test_security_headers_middleware.py @@ -24,6 +24,32 @@ async def test_security_headers_middleware_passes_through_non_http_scope() -> No assert called is True +@pytest.mark.asyncio +async def test_security_headers_middleware_appends_lowercase_raw_header_names() -> None: + sent_messages: list[dict[str, object]] = [] + + async def app(scope, receive, send): # type: ignore[no-untyped-def] + _ = scope + _ = receive + await send({"type": "http.response.start", "status": 200, "headers": []}) + await send({"type": "http.response.body", "body": b"", "more_body": False}) + + async def capture(message): # type: ignore[no-untyped-def] + sent_messages.append(message) + + middleware = SecurityHeadersMiddleware(app, x_frame_options="SAMEORIGIN") + await middleware({"type": "http", "method": "GET", "path": "/", "headers": []}, lambda: None, capture) + + response_start = next( + message for message in sent_messages if message.get("type") == "http.response.start" + ) + headers = response_start.get("headers") + assert isinstance(headers, list) + header_names = {name for name, _value in headers} + assert b"x-frame-options" in header_names + assert b"X-Frame-Options" not in header_names + + def test_security_headers_middleware_injects_configured_headers() -> None: app = FastAPI() app.add_middleware(