Skip to content

fix(starlette): Stop eagerly consuming request bodies for streamed spans - #6282

Merged
alexander-alderman-webb merged 22 commits into
masterfrom
webb/starlette/request-body-async
Jun 9, 2026
Merged

alexander-alderman-webb merged 22 commits into
masterfrom
webb/starlette/request-body-async

merge master

88b6b7a
Select commit
Loading
Failed to load commit list.
@sentry/warden / warden: find-bugs completed Jun 9, 2026 in 20m 26s

2 issues

find-bugs: Found 2 issues (1 high, 1 low)

High

PII scrubbing bypassed for request body in streamed span attributes - `tests/integrations/starlette/test_starlette.py:394`

For streamed spans, _get_cached_request_body_attribute serializes the cached request body (request._json or request._form) directly with json.dumps and writes it verbatim to the HTTP_REQUEST_BODY_DATA span attribute, without applying any PII/data scrubbing. Sensitive fields such as password are therefore sent to Sentry in plaintext on the span, even though the same form data is correctly redacted to [Filtered] in the corresponding event/transaction request.data. The code comment acknowledges sanitization still needs to be implemented (planned for before_send_span), so currently no scrubbing occurs on this path.

Low

Streamed-span request-body attachment in `finally` lacks `capture_internal_exceptions()` guard - `sentry_sdk/integrations/starlette.py:563-576`

In _wrap_async_handler, the streamed-span body attachment now runs inside a finally block that calls _get_cached_request_body_attribute (which calls json.dumps) and current_span._segment.set_attribute(...) with no exception guard. The equivalent prior helper _set_request_body_data_on_streaming_segment wrapped the same set_attribute call in with capture_internal_exceptions():. Removing that guard means any exception raised by the SDK's own body-attachment logic propagates: in the error path it replaces (masks) the handler's original exception because it is raised from a finally block; in the success path it converts an otherwise-successful response into a failure. The realistic trigger is narrow — request._json is normally produced by Starlette's json.loads and is therefore JSON-serializable, and form values are strings or handled UploadFiles — so json.dumps rarely fails. The concrete, definite regression is that SDK instrumentation code is no longer isolated from the application's control flow, which violates the SDK invariant that internal failures must never surface to the host application.


⏱ 19m 5s · 3.5M in / 104.8k out · $3.63

Annotations

Check failure on line 394 in tests/integrations/starlette/test_starlette.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

PII scrubbing bypassed for request body in streamed span attributes

For streamed spans, `_get_cached_request_body_attribute` serializes the cached request body (`request._json` or `request._form`) directly with `json.dumps` and writes it verbatim to the `HTTP_REQUEST_BODY_DATA` span attribute, without applying any PII/data scrubbing. Sensitive fields such as `password` are therefore sent to Sentry in plaintext on the span, even though the same form data is correctly redacted to `[Filtered]` in the corresponding event/transaction `request.data`. The code comment acknowledges sanitization still needs to be implemented (planned for `before_send_span`), so currently no scrubbing occurs on this path.