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 - [Prevented Swallowing of Unhandled Exception Tracebacks]
**Vulnerability:** The global `@app.exception_handler(Exception)` in `src/tacet/serve/server.py` suppressed unhandled exceptions without logging them. This bypassed Starlette's `ServerErrorMiddleware` logging, causing silent server-side failures and hiding critical errors.
**Learning:** Overriding the default exception handler to add security headers removes the framework's default behavior of logging unhandled exceptions.
**Prevention:** Always explicitly log the exception (e.g., `logging.error("...", exc_info=_exc)`) when defining a generic catch-all exception handler in FastAPI.
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:
logging.error("Unhandled server exception", exc_info=_exc)
response = PlainTextResponse("Internal Server Error", status_code=500)
return _apply_security_headers(response, request.url.path)

Expand Down
Loading