Skip to content

Commit 486f0bc

Browse files
committed
make sure host header is not filtered when being added to the url
1 parent 16ed0c8 commit 486f0bc

3 files changed

Lines changed: 73 additions & 6 deletions

File tree

sentry_sdk/integrations/_asgi_common.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,13 @@ def _get_request_data(
115115
if ty in ("http", "websocket"):
116116
request_data["method"] = asgi_scope.get("method")
117117

118-
request_data["headers"] = headers = _filter_headers(
119-
_get_headers(asgi_scope),
118+
headers = _get_headers(asgi_scope)
119+
120+
request_data["headers"] = _filter_headers(
121+
headers,
120122
use_annotated_value=False,
121123
)
124+
122125
request_data["query_string"] = _get_query(asgi_scope)
123126

124127
request_data["url"] = _get_url(
@@ -149,8 +152,10 @@ def _get_request_attributes(
149152
if asgi_scope.get("method"):
150153
attributes["http.request.method"] = asgi_scope["method"].upper()
151154

152-
headers = _filter_headers(_get_headers(asgi_scope))
153-
for header, value in headers.items():
155+
headers = _get_headers(asgi_scope)
156+
157+
filtered_headers = _filter_headers(headers, use_annotated_value=False)
158+
for header, value in filtered_headers.items():
154159
attributes[f"http.request.header.{header.lower()}"] = value
155160

156161
if should_send_default_pii():

sentry_sdk/integrations/_wsgi_common.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
from sentry_sdk._types import Event, HttpStatusCodeRange
2525

26+
2627
SENSITIVE_ENV_KEYS = (
2728
"REMOTE_ADDR",
2829
"HTTP_X_FORWARDED_FOR",
@@ -212,7 +213,7 @@ def _is_json_content_type(ct: "Optional[str]") -> bool:
212213
def _filter_headers(
213214
headers: "Mapping[str, str]",
214215
use_annotated_value: bool = True,
215-
) -> "Mapping[str, Union[str, AnnotatedValue]]":
216+
) -> "Mapping[str, Union[AnnotatedValue, str]]":
216217
client_options = sentry_sdk.get_client().options
217218

218219
if has_data_collection_enabled(client_options):

tests/integrations/asgi/test_asgi.py

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@
55

66
import sentry_sdk
77
from sentry_sdk import capture_message
8-
from sentry_sdk.integrations._asgi_common import _get_headers, _get_ip
8+
from sentry_sdk.integrations._asgi_common import (
9+
_get_headers,
10+
_get_ip,
11+
_get_request_attributes,
12+
_get_request_data,
13+
_RootPathInPath,
14+
)
915
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware, _looks_like_asgi3
1016
from sentry_sdk.tracing import TransactionSource
1117

@@ -831,6 +837,61 @@ def test_get_headers():
831837
}
832838

833839

840+
def test_get_request_data_url_with_filtered_host(sentry_init):
841+
# allowlist mode in data collection that does not allow "host" scrubs the host header value,
842+
# but the reported URL must still resolve via rather than embedding the substituted "[Filtered]" value.
843+
sentry_init(
844+
_experiments={
845+
"data_collection": {
846+
"http_headers": {"request": {"mode": "allowlist", "terms": []}}
847+
}
848+
}
849+
)
850+
851+
scope = {
852+
"type": "http",
853+
"method": "GET",
854+
"scheme": "http",
855+
"server": ("example.com", 80),
856+
"path": "/foo",
857+
"query_string": b"",
858+
"headers": [(b"host", b"example.com")],
859+
}
860+
861+
request_data = _get_request_data(scope, _RootPathInPath.EXCLUDED)
862+
863+
assert request_data["headers"]["host"] == "[Filtered]"
864+
assert request_data["url"] == "http://example.com/foo"
865+
866+
867+
def test_get_request_attributes_url_with_filtered_host(sentry_init):
868+
# As with _get_request_data, an allowlist mode that does not allow "host"
869+
# scrubs the host header value, but "url.full" must still resolve rather than embedding the substituted value.
870+
sentry_init(
871+
send_default_pii=True,
872+
_experiments={
873+
"data_collection": {
874+
"http_headers": {"request": {"mode": "allowlist", "terms": []}}
875+
}
876+
},
877+
)
878+
879+
scope = {
880+
"type": "http",
881+
"method": "GET",
882+
"scheme": "http",
883+
"server": ("example.com", 80),
884+
"path": "/foo",
885+
"query_string": b"somevalue=123",
886+
"headers": [(b"host", b"example.com")],
887+
}
888+
889+
attributes = _get_request_attributes(scope, _RootPathInPath.EXCLUDED)
890+
891+
assert attributes["http.request.header.host"] == "[Filtered]"
892+
assert attributes["url.full"] == "http://example.com/foo?somevalue=123"
893+
894+
834895
@pytest.mark.asyncio
835896
@pytest.mark.parametrize(
836897
"request_url,transaction_style,expected_transaction_name,expected_transaction_source",

0 commit comments

Comments
 (0)