diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 80d5d5e..1d0e11e 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -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. diff --git a/src/tacet/serve/server.py b/src/tacet/serve/server.py index 2df2279..99e1d8a 100644 --- a/src/tacet/serve/server.py +++ b/src/tacet/serve/server.py @@ -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)