Skip to content

Comments

🛡️ Sentinel: [MEDIUM] Add HTTP security headers#605

Open
anchapin wants to merge 1 commit intomainfrom
sentinel-security-headers-9491554518218487140
Open

🛡️ Sentinel: [MEDIUM] Add HTTP security headers#605
anchapin wants to merge 1 commit intomainfrom
sentinel-security-headers-9491554518218487140

Conversation

@anchapin
Copy link
Owner

🚨 Severity: MEDIUM
💡 Vulnerability: Missing HTTP security headers (defense in depth).
🎯 Impact: Reduces risk of clickjacking, MIME-sniffing, and XSS attacks.
🔧 Fix: Implemented and added SecurityHeadersMiddleware to backend/src/main.py.
✅ Verification: Added unit test in backend/src/tests/unit/test_security_headers.py verifying presence of headers.


PR created automatically by Jules for task 9491554518218487140 started by @anchapin

- Implements SecurityHeadersMiddleware in backend/src/services/security_headers.py
- Adds middleware to backend/src/main.py
- Adds unit test in backend/src/tests/unit/test_security_headers.py
- Headers added: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy

Co-authored-by: anchapin <6326294+anchapin@users.noreply.github.com>
@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings February 23, 2026 00:46
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @anchapin, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds HTTP security headers to the FastAPI backend by implementing a SecurityHeadersMiddleware that sets defense-in-depth headers (X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy) on all responses. The change aims to mitigate clickjacking, MIME-sniffing, and XSS attacks at the backend API layer.

Changes:

  • Created new SecurityHeadersMiddleware in backend/src/services/security_headers.py to add security headers to all responses
  • Registered the middleware in backend/src/main.py after rate limiting middleware
  • Added unit test in backend/src/tests/unit/test_security_headers.py to verify headers are present

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

File Description
backend/src/services/security_headers.py New middleware implementation that adds four security headers to all HTTP responses
backend/src/main.py Middleware registration added after rate limiting middleware setup
backend/src/tests/unit/test_security_headers.py Unit test verifying security headers are present in responses

Comment on lines +1 to +6
from fastapi.testclient import TestClient
from src.main import app

client = TestClient(app)

def test_security_headers():
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test should use the pytest fixture pattern instead of creating a TestClient directly. The codebase has a centralized client fixture in conftest.py (backend/src/tests/conftest.py:103-134) that properly handles database mocking and dependency overrides. Using this fixture ensures consistency across tests and avoids potential issues with database initialization and cleanup. Refactor to use the client fixture as a parameter.

Suggested change
from fastapi.testclient import TestClient
from src.main import app
client = TestClient(app)
def test_security_headers():
def test_security_headers(client):

Copilot uses AI. Check for mistakes.
headers = response.headers
assert headers["X-Content-Type-Options"] == "nosniff"
assert headers["X-Frame-Options"] == "DENY"
assert headers["X-XSS-Protection"] == "1; mode=block"
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test should verify that the deprecated X-XSS-Protection header is not present, rather than asserting it equals "1; mode=block". Since this header is deprecated and modern browsers no longer support it, the test should be updated to reflect the corrected implementation once the security header is removed from the middleware.

Suggested change
assert headers["X-XSS-Protection"] == "1; mode=block"
assert "X-XSS-Protection" not in headers

Copilot uses AI. Check for mistakes.
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a Content-Security-Policy (CSP) header to the backend middleware for defense in depth. While Nginx already sets CSP (frontend/nginx.conf:52), adding it at the backend level ensures API responses are protected even if accessed directly or if the Nginx layer is bypassed. This is especially important for the backend API running on port 8080 which may be accessed directly in development or certain deployment scenarios.

Suggested change
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
if "Content-Security-Policy" not in response.headers:
response.headers[
"Content-Security-Policy"
] = "default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'"

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +13
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding Strict-Transport-Security (HSTS) header for HTTPS deployments. While the current setup uses HTTP (port 80 in Nginx), production deployments should enforce HTTPS. Adding the header conditionally based on the request scheme or environment variable would improve security posture when deployed with TLS. Example: "Strict-Transport-Security: max-age=31536000; includeSubDomains".

Copilot uses AI. Check for mistakes.
async def dispatch(self, request: Request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The X-Frame-Options header value conflicts with the Nginx configuration. The backend sets "DENY" while Nginx sets "SAMEORIGIN" (frontend/nginx.conf:48). This creates inconsistent behavior where responses from the backend have stricter settings than those served by Nginx. The values should be aligned - either both use "DENY" for maximum security or both use "SAMEORIGIN" for flexibility.

Suggested change
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-Frame-Options"] = "SAMEORIGIN"

Copilot uses AI. Check for mistakes.
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Referrer-Policy header value conflicts with the Nginx configuration. The backend sets "strict-origin-when-cross-origin" while Nginx sets "no-referrer-when-downgrade" (frontend/nginx.conf:51). This creates inconsistent security postures. The backend's value is more privacy-preserving and should be aligned across both layers. Consider updating Nginx to match this setting or documenting why different policies are needed.

Suggested change
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
# NOTE: This must stay aligned with the Referrer-Policy set in Nginx (frontend/nginx.conf).
response.headers["Referrer-Policy"] = "no-referrer-when-downgrade"

Copilot uses AI. Check for mistakes.
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The X-XSS-Protection header is deprecated and should be removed. Modern browsers have deprecated this header in favor of Content-Security-Policy (CSP). Chrome, Edge, and Safari have removed support for this header, and it can introduce security vulnerabilities in older browsers. Since Nginx already sets a comprehensive CSP header (frontend/nginx.conf:52), this header is redundant and potentially harmful. Consider removing it or replacing it with CSP if not already present.

Suggested change
response.headers["X-XSS-Protection"] = "1; mode=block"

Copilot uses AI. Check for mistakes.
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.

1 participant