Skip to content

Commit 7ce81ec

Browse files
authored
fix(stdlib): Gate url.full and http.query behind send_default_pii (#6666)
`url.full`, `url.query`, and `url.fragment` span attributes set by the stdlib (httplib) integration are now gated behind `send_default_pii`, consistent with the same fix already applied to the aiohttp and wsgi integrations. These attributes can contain sensitive query parameters or path fragments, so they should only be captured when the user has explicitly opted in. `http.fragment` on the legacy span data path is unconditionally omitted since fragments are never sent to the server and carry no useful diagnostic value regardless of PII setting. Fixes #PY-2557 Fixes #6665
1 parent 2545570 commit 7ce81ec

3 files changed

Lines changed: 31 additions & 17 deletions

File tree

sentry_sdk/integrations/stdlib.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import sentry_sdk
99
from sentry_sdk.consts import OP, SPANDATA
1010
from sentry_sdk.integrations import Integration
11-
from sentry_sdk.scope import add_global_event_processor
11+
from sentry_sdk.scope import add_global_event_processor, should_send_default_pii
1212
from sentry_sdk.traces import StreamedSpan
1313
from sentry_sdk.tracing import Span
1414
from sentry_sdk.tracing_utils import (
@@ -124,10 +124,10 @@ def putrequest(
124124
},
125125
)
126126

127-
if parsed_url is not None:
127+
if parsed_url is not None and should_send_default_pii():
128+
span.set_attribute(SPANDATA.URL_FRAGMENT, parsed_url.fragment)
128129
span.set_attribute(SPANDATA.URL_FULL, parsed_url.url)
129130
span.set_attribute(SPANDATA.URL_QUERY, parsed_url.query)
130-
span.set_attribute(SPANDATA.URL_FRAGMENT, parsed_url.fragment)
131131

132132
set_on_span = span.set_attribute
133133

@@ -141,9 +141,9 @@ def putrequest(
141141

142142
span.set_data(SPANDATA.HTTP_METHOD, method)
143143
if parsed_url is not None:
144+
span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment)
144145
span.set_data("url", parsed_url.url)
145146
span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query)
146-
span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment)
147147

148148
set_on_span = span.set_data
149149

tests/integrations/requests/test_requests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414

1515
def test_crumb_capture(sentry_init, capture_events):
16-
sentry_init(integrations=[StdlibIntegration()])
16+
sentry_init(integrations=[StdlibIntegration()], send_default_pii=True)
1717
events = capture_events()
1818

1919
url = f"http://localhost:{PORT}/hello-world" # noqa:E231
@@ -51,7 +51,7 @@ def test_crumb_capture(sentry_init, capture_events):
5151
],
5252
)
5353
def test_crumb_capture_client_error(sentry_init, capture_events, status_code, level):
54-
sentry_init(integrations=[StdlibIntegration()])
54+
sentry_init(integrations=[StdlibIntegration()], send_default_pii=True)
5555

5656
events = capture_events()
5757

tests/integrations/stdlib/test_httplib.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def create_chunked_server():
7777

7878

7979
def test_crumb_capture(sentry_init, capture_events):
80-
sentry_init(integrations=[StdlibIntegration()])
80+
sentry_init(integrations=[StdlibIntegration()], send_default_pii=True)
8181
events = capture_events()
8282

8383
url = "http://localhost:{}/some/random/url".format(PORT)
@@ -113,7 +113,7 @@ def test_crumb_capture(sentry_init, capture_events):
113113
],
114114
)
115115
def test_crumb_capture_client_error(sentry_init, capture_events, status_code, level):
116-
sentry_init(integrations=[StdlibIntegration()])
116+
sentry_init(integrations=[StdlibIntegration()], send_default_pii=True)
117117
events = capture_events()
118118

119119
url = f"http://localhost:{PORT}/status/{status_code}" # noqa:E231
@@ -151,7 +151,11 @@ def before_breadcrumb(crumb, hint):
151151
crumb["data"]["extra"] = "foo"
152152
return crumb
153153

154-
sentry_init(integrations=[StdlibIntegration()], before_breadcrumb=before_breadcrumb)
154+
sentry_init(
155+
integrations=[StdlibIntegration()],
156+
before_breadcrumb=before_breadcrumb,
157+
send_default_pii=True,
158+
)
155159
events = capture_events()
156160

157161
url = "http://localhost:{}/some/random/url".format(PORT)
@@ -203,7 +207,7 @@ def test_httplib_misuse(sentry_init, capture_events, request):
203207
wrongly.
204208
"""
205209

206-
sentry_init()
210+
sentry_init(send_default_pii=True)
207211
events = capture_events()
208212

209213
conn = HTTPConnection("localhost", PORT)
@@ -1136,15 +1140,18 @@ def test_http_timeout(
11361140

11371141
@pytest.mark.parametrize("tunnel_port", [8080, None])
11381142
@pytest.mark.parametrize("span_streaming", [True, False])
1143+
@pytest.mark.parametrize("send_default_pii", [True, False])
11391144
def test_proxy_http_tunnel(
11401145
sentry_init,
11411146
capture_events,
11421147
capture_items,
11431148
tunnel_port,
11441149
span_streaming,
1150+
send_default_pii,
11451151
):
11461152
sentry_init(
11471153
traces_sample_rate=1.0,
1154+
send_default_pii=send_default_pii,
11481155
_experiments={"trace_lifecycle": "stream" if span_streaming else "static"},
11491156
)
11501157

@@ -1154,7 +1161,7 @@ def test_proxy_http_tunnel(
11541161
with sentry_sdk.traces.start_span(name="custom parent"):
11551162
conn = HTTPConnection("localhost", PROXY_PORT)
11561163
conn.set_tunnel("api.example.com", tunnel_port)
1157-
conn.request("GET", "/foo")
1164+
conn.request("GET", "/foo?bar=1")
11581165
conn.getresponse()
11591166

11601167
sentry_sdk.flush()
@@ -1167,31 +1174,38 @@ def test_proxy_http_tunnel(
11671174

11681175
port_modifier = f":{tunnel_port}" if tunnel_port else ""
11691176
assert span["name"] == f"GET http://api.example.com{port_modifier}/foo"
1170-
assert (
1171-
span["attributes"][SPANDATA.URL_FULL]
1172-
== f"http://api.example.com{port_modifier}/foo"
1173-
)
11741177
assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET"
11751178
assert span["attributes"][SPANDATA.NETWORK_PEER_ADDRESS] == "localhost"
11761179
assert span["attributes"][SPANDATA.NETWORK_PEER_PORT] == PROXY_PORT
1180+
1181+
if send_default_pii:
1182+
assert (
1183+
span["attributes"][SPANDATA.URL_FULL]
1184+
== f"http://api.example.com{port_modifier}/foo"
1185+
)
1186+
assert span["attributes"][SPANDATA.URL_QUERY] == "bar=1"
1187+
else:
1188+
assert SPANDATA.URL_FULL not in span["attributes"]
1189+
assert SPANDATA.URL_QUERY not in span["attributes"]
11771190
else:
11781191
events = capture_events()
11791192

11801193
with start_transaction(name="test_transaction"):
11811194
conn = HTTPConnection("localhost", PROXY_PORT)
11821195
conn.set_tunnel("api.example.com", tunnel_port)
1183-
conn.request("GET", "/foo")
1196+
conn.request("GET", "/foo?bar=1")
11841197
conn.getresponse()
11851198

11861199
(event,) = events
11871200
(span,) = event["spans"]
11881201

11891202
port_modifier = f":{tunnel_port}" if tunnel_port else ""
11901203
assert span["description"] == f"GET http://api.example.com{port_modifier}/foo"
1191-
assert span["data"]["url"] == f"http://api.example.com{port_modifier}/foo"
11921204
assert span["data"][SPANDATA.HTTP_METHOD] == "GET"
11931205
assert span["data"][SPANDATA.NETWORK_PEER_ADDRESS] == "localhost"
11941206
assert span["data"][SPANDATA.NETWORK_PEER_PORT] == PROXY_PORT
1207+
assert span["data"]["url"] == f"http://api.example.com{port_modifier}/foo"
1208+
assert span["data"][SPANDATA.HTTP_QUERY] == "bar=1"
11951209

11961210

11971211
@pytest.mark.parametrize("span_streaming", [True, False])

0 commit comments

Comments
 (0)