SECURITY: generic API 500 responses expose internal Python tracebacks to clients #174

Open
opened 2026-09-09 15:05:23 +00:00 by nsaspy · 0 comments
Owner

Finding

helpers/api.py::ApiHandler.handle_request() catches arbitrary exceptions and returns:

error = format_error(e)
PrintStyle.error(f"API error: {error}")
return Response(response=error, status=500, mimetype="text/plain")

helpers/errors.py::format_error() includes a Python traceback with source file paths, call stack, exception text and potentially values interpolated into exception messages.

Therefore unexpected errors from built-in, plugin, or user API handlers are returned verbatim to the HTTP client. This exposes implementation details and can leak sensitive path/config/value information when an exception contains it. If UI authentication is intentionally unset, requires_auth permits the request, increasing the importance of a safe production error boundary.

Direction

Separate client-safe errors from server diagnostics:

  • generate a request/error correlation ID
  • log the detailed traceback server-side with that ID
  • return a generic structured 500 payload to clients
  • allow an explicit development/debug mode to expose traces locally if desired, but never make detailed traces the default wire response
  • preserve intentional user-facing validation errors as typed 4xx responses rather than treating everything as generic 500

Acceptance

  • Unexpected API exceptions do not return Python stack frames, server filesystem paths or raw exception values to the client by default.
  • Server logs retain the detailed traceback with a correlation ID.
  • Client response includes a stable error code/correlation ID usable for diagnosis.
  • Plugin/user API handlers receive the same error boundary.
  • Explicit validation/authorization failures keep appropriate 4xx status and safe messages.
  • Development trace exposure, if retained, is explicit and cannot accidentally activate just because authentication is unset.
  • Regression test raises an exception containing a synthetic secret/path and proves neither appears in the default HTTP response.

Mirrored from lost-rob0t/a0-symbolics#36 via tracker sync.

## Finding `helpers/api.py::ApiHandler.handle_request()` catches arbitrary exceptions and returns: ```python error = format_error(e) PrintStyle.error(f"API error: {error}") return Response(response=error, status=500, mimetype="text/plain") ``` `helpers/errors.py::format_error()` includes a Python traceback with source file paths, call stack, exception text and potentially values interpolated into exception messages. Therefore unexpected errors from built-in, plugin, or user API handlers are returned verbatim to the HTTP client. This exposes implementation details and can leak sensitive path/config/value information when an exception contains it. If UI authentication is intentionally unset, `requires_auth` permits the request, increasing the importance of a safe production error boundary. ## Direction Separate client-safe errors from server diagnostics: - generate a request/error correlation ID - log the detailed traceback server-side with that ID - return a generic structured 500 payload to clients - allow an explicit development/debug mode to expose traces locally if desired, but never make detailed traces the default wire response - preserve intentional user-facing validation errors as typed 4xx responses rather than treating everything as generic 500 ## Acceptance - [ ] Unexpected API exceptions do not return Python stack frames, server filesystem paths or raw exception values to the client by default. - [ ] Server logs retain the detailed traceback with a correlation ID. - [ ] Client response includes a stable error code/correlation ID usable for diagnosis. - [ ] Plugin/user API handlers receive the same error boundary. - [ ] Explicit validation/authorization failures keep appropriate 4xx status and safe messages. - [ ] Development trace exposure, if retained, is explicit and cannot accidentally activate just because authentication is unset. - [ ] Regression test raises an exception containing a synthetic secret/path and proves neither appears in the default HTTP response. --- *Mirrored from [`lost-rob0t/a0-symbolics#36`](https://github.com/lost-rob0t/a0-symbolics/issues/36)* via tracker sync.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/a0-symbolics#174
No description provided.