Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,8 @@
**Vulnerability:** The FastAPI application was missing the `Referrer-Policy` security header, which could leak sensitive path information or query parameters via the `Referer` header to external sites when navigating away from the application.
**Learning:** Even when setting strict `Content-Security-Policy` and `X-Frame-Options`, `Referrer-Policy` is needed to prevent cross-origin information leakage on outbound requests.
**Prevention:** Always include `Referrer-Policy: no-referrer` in the global security headers middleware to strictly drop referrer information on all outbound requests.

## 2025-02-21 - [Fix swallowed exceptions in custom global error handler]
**Vulnerability:** The FastAPI application used a custom global exception handler (`@app.exception_handler(Exception)`) to apply security headers to 500 error responses, but this overrode Starlette's built-in `ServerErrorMiddleware` logging. It returned a plain 500 response but silently swallowed the traceback on the server-side, making debugging impossible and masking potential exploitation attempts.
**Learning:** Overriding the default global Exception handler in FastAPI or Starlette bypasses the built-in traceback logging. You must explicitly log the exception if you implement a generic catch-all exception handler to avoid silently swallowing server-side tracebacks.
**Prevention:** In custom generic exception handlers, explicitly log the exception (e.g., using `log.error(..., exc_info=_exc)`) before returning the generic 500 HTTP response.
1 change: 1 addition & 0 deletions src/tacet/serve/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ async def add_security_headers(request: Request, call_next):

@app.exception_handler(Exception)
async def unhandled_exception_handler(request: Request, _exc: Exception) -> Response:
log.error("Unhandled server error", exc_info=_exc)
response = PlainTextResponse("Internal Server Error", status_code=500)
return _apply_security_headers(response, request.url.path)

Expand Down
Loading