diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 80d5d5e..d79bedd 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 - [Prevent swallowed exception tracebacks in Exception Handler] +**Vulnerability:** The `unhandled_exception_handler` middleware caught all internal exceptions returning generic 'Internal Server Error' 500 response while ignoring explicitly logging the exceptions `log.error`, resulting in silently swallowed tracebacks server side. +**Learning:** Returning a safe generic error response prevents internal application stack trace exposure, but it's important to make sure exceptions tracebacks are logged properly on the server side to detect attacks/bugs in the internal app code stack. +**Prevention:** Ensured the custom unhandled exception handler properly logs the exception using `log.error("Unhandled exception", exc_info=_exc)` instead of ignoring it silently. diff --git a/src/tacet/serve/server.py b/src/tacet/serve/server.py index 2df2279..656faff 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: + log.error("Unhandled exception", exc_info=_exc) response = PlainTextResponse("Internal Server Error", status_code=500) return _apply_security_headers(response, request.url.path)