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.

## 2026-07-28 - Explicitly Log Exceptions in Custom FastAPI Exception Handlers
**Vulnerability:** When a custom global exception handler (`@app.exception_handler(Exception)`) is registered in FastAPI (e.g., to inject security headers on 500 error responses), it bypasses Starlette's built-in `ServerErrorMiddleware` logging.
**Learning:** Failing to explicitly log the exception in the custom handler causes server-side tracebacks to be silently swallowed, blinding operators to server-side errors and potential exploitation attempts.
**Prevention:** Always explicitly log exceptions (`logging.error(..., exc_info=_exc)`) within custom global exception handlers.
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