Skip to content

ref(integrations): route HTTP header filtering through data collection config#6788

Merged
ericapisani merged 26 commits into
masterfrom
py-2584-update-wsgi-filter-headers
Jul 22, 2026
Merged

ref(integrations): route HTTP header filtering through data collection config#6788
ericapisani merged 26 commits into
masterfrom
py-2584-update-wsgi-filter-headers

add test coverage within the wsgi test file

951c408
Select commit
Loading
Failed to load commit list.
@sentry/warden / warden completed Jul 9, 2026 in 0s

3 issues

Medium

IP headers (X-Forwarded-For / X-Real-Ip) leak when data_collection is enabled with default header denylist - `sentry_sdk/integrations/_wsgi_common.py:7-9`

When a user supplies an explicit data_collection config, _filter_headers routes header scrubbing through _apply_key_value_collection_filtering. If http_headers.request is omitted, _http_headers_from_value resolves it to {"mode": "denylist"} with no extra terms, so only the built-in _SENSITIVE_DENYLIST applies. That denylist contains none of the terms needed to match x-forwarded-for or x-real-ip, so those IP-address headers (PII) pass through unfiltered. This is a regression relative to the send_default_pii-derived mapping (_map_from_send_default_pii), which — when PII is off — explicitly adds the terms ["forwarded", "-ip", "remote-", "via", "-user"] and the legacy SENSITIVE_HEADERS path which scrubs X_FORWARDED_FOR and X_REAL_IP. A user who enables data_collection for an unrelated purpose (e.g. cookies) inadvertently starts sending client IP headers that were previously scrubbed.

Low

`use_annotated_value` ignored in data-collection branch of `_filter_headers` - `sentry_sdk/integrations/_wsgi_common.py:222-235`

When data collection is enabled, _filter_headers delegates to _apply_key_value_collection_filtering without passing a substitute, so filtered/sensitive header values always become the string SENSITIVE_DATA_SUBSTITUTE regardless of the use_annotated_value argument. The legacy else branch instead uses AnnotatedValue.removed_because_over_size_limit() when use_annotated_value=True. Data is still scrubbed in both cases, so this is not a leak, but event-processor callers (e.g. wsgi.py:357, aiohttp.py:465, aws_lambda.py:415, quart.py:250, tornado.py:279, sanic.py:427, gcp.py:243) that rely on the default use_annotated_value=True will silently lose the AnnotatedValue _meta annotation whenever data_collection is configured. Consider deriving a substitute from use_annotated_value and passing it to _apply_key_value_collection_filtering (and the cookie loop) to preserve consistent behavior.

`url.full`, `url.path`, `http.query`, and `client.address` are dropped in `_get_request_attributes` when only `data_collection` is configured - `tests/integrations/asgi/test_asgi.py:875-906`

_get_request_attributes in _asgi_common.py gates http.query, url.path, url.full, and client.address behind should_send_default_pii(). That helper reads only the raw send_default_pii option and returns False when a user configures data_collection alone (without send_default_pii). Because this branch routes only HTTP header filtering through data_collection while these URL/query/client attributes still key off send_default_pii, a user who adopts data_collection as a replacement for send_default_pii will silently lose these OTel span attributes even though their data_collection config (e.g. query_params defaults to collect) implies they should be captured. The two new tests mask this gap by passing send_default_pii=True alongside data_collection, which also emits an unasserted DeprecationWarning from _resolve_data_collection. This is dropped telemetry (fail-safe direction), not over-collection, and likely reflects an incomplete migration, so severity is low.

4 skills analyzed
Skill Findings Duration Cost
security-review 0 2m 38s $0.62
code-review 1 7m 16s $2.95
find-bugs 2 24m 3s $6.87
skill-scanner 0 11m 33s $0.19

⏱ 45m 31s · 7.3M in / 310.4k out · $10.64