Skip to content

Commit 12fbaa5

Browse files
committed
Add separate pii_denylist to EventScrubber and run it always
1 parent 4b361c5 commit 12fbaa5

File tree

4 files changed

+68
-12
lines changed

4 files changed

+68
-12
lines changed

sentry_sdk/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def _get_options(*args, **kwargs):
125125
rv["traces_sample_rate"] = 1.0
126126

127127
if rv["event_scrubber"] is None:
128-
rv["event_scrubber"] = EventScrubber()
128+
rv["event_scrubber"] = EventScrubber(send_default_pii=rv["send_default_pii"])
129129

130130
if rv["socket_options"] and not isinstance(rv["socket_options"], list):
131131
logger.warning(
@@ -526,7 +526,7 @@ def _prepare_event(
526526

527527
if event is not None:
528528
event_scrubber = self.options["event_scrubber"]
529-
if event_scrubber and not self.options["send_default_pii"]:
529+
if event_scrubber:
530530
event_scrubber.scrub_event(event)
531531

532532
# Postprocess the event here so that annotated types do

sentry_sdk/scrubber.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,17 @@
2525
"privatekey",
2626
"private_key",
2727
"token",
28-
"ip_address",
2928
"session",
3029
# django
3130
"csrftoken",
3231
"sessionid",
3332
# wsgi
34-
"remote_addr",
3533
"x_csrftoken",
3634
"x_forwarded_for",
3735
"set_cookie",
3836
"cookie",
3937
"authorization",
4038
"x_api_key",
41-
"x_forwarded_for",
42-
"x_real_ip",
4339
# other common names used in the wild
4440
"aiohttp_session", # aiohttp
4541
"connect.sid", # Express
@@ -55,11 +51,35 @@
5551
"XSRF-TOKEN", # Angular, Laravel
5652
]
5753

54+
DEFAULT_PII_DENYLIST = [
55+
"x_forwarded_for",
56+
"x_real_ip",
57+
"ip_address",
58+
"remote_addr",
59+
]
60+
5861

5962
class EventScrubber(object):
60-
def __init__(self, denylist=None, recursive=False):
61-
# type: (Optional[List[str]], bool) -> None
62-
self.denylist = DEFAULT_DENYLIST if denylist is None else denylist
63+
def __init__(
64+
self, denylist=None, recursive=False, send_default_pii=False, pii_denylist=None
65+
):
66+
# type: (Optional[List[str]], bool, bool, Optional[List[str]]) -> None
67+
"""
68+
A scrubber that goes through the event payload and removes sensitive data configured through denylists.
69+
70+
:param denylist: A security denylist that is always scrubbed, defaults to DEFAULT_DENYLIST.
71+
:param recursive: Whether to scrub the event payload recursively, default False.
72+
:param send_default_pii: Whether pii is sending is on, pii fields are not scrubbed.
73+
:param pii_denylist: The denylist to use for scrubbing when pii is not sent, defaults to DEFAULT_PII_DENYLIST.
74+
"""
75+
self.denylist = DEFAULT_DENYLIST.copy() if denylist is None else denylist
76+
77+
if not send_default_pii:
78+
pii_denylist = (
79+
DEFAULT_PII_DENYLIST.copy() if pii_denylist is None else pii_denylist
80+
)
81+
self.denylist += pii_denylist
82+
6383
self.denylist = [x.lower() for x in self.denylist]
6484
self.recursive = recursive
6585

tests/integrations/django/asgi/test_asgi.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ async def test_trace_from_headers_if_performance_disabled(sentry_init, capture_e
434434
[(b"content-type", b"application/json")],
435435
"post_echo_async",
436436
b'{"username":"xyz","password":"xyz"}',
437-
{"username": "xyz", "password": "xyz"},
437+
{"username": "xyz", "password": "[Filtered]"},
438438
),
439439
(
440440
True,
@@ -453,7 +453,7 @@ async def test_trace_from_headers_if_performance_disabled(sentry_init, capture_e
453453
],
454454
"post_echo_async",
455455
BODY_FORM,
456-
{"password": "hello123", "photo": "", "username": "Jane"},
456+
{"password": "[Filtered]", "photo": "", "username": "Jane"},
457457
),
458458
(
459459
False,

tests/test_scrubber.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def test_request_scrubbing(sentry_init, capture_events):
2525
"COOKIE": "secret",
2626
"authorization": "Bearer bla",
2727
"ORIGIN": "google.com",
28+
"ip_address": "127.0.0.1",
2829
},
2930
"cookies": {
3031
"sessionid": "secret",
@@ -45,6 +46,7 @@ def test_request_scrubbing(sentry_init, capture_events):
4546
"COOKIE": "[Filtered]",
4647
"authorization": "[Filtered]",
4748
"ORIGIN": "google.com",
49+
"ip_address": "[Filtered]",
4850
},
4951
"cookies": {"sessionid": "[Filtered]", "foo": "bar"},
5052
"data": {"token": "[Filtered]", "foo": "bar"},
@@ -54,12 +56,39 @@ def test_request_scrubbing(sentry_init, capture_events):
5456
"headers": {
5557
"COOKIE": {"": {"rem": [["!config", "s"]]}},
5658
"authorization": {"": {"rem": [["!config", "s"]]}},
59+
"ip_address": {"": {"rem": [["!config", "s"]]}},
5760
},
5861
"cookies": {"sessionid": {"": {"rem": [["!config", "s"]]}}},
5962
"data": {"token": {"": {"rem": [["!config", "s"]]}}},
6063
}
6164

6265

66+
def test_ip_address_not_scrubbed_when_pii_enabled(sentry_init, capture_events):
67+
sentry_init(send_default_pii=True)
68+
events = capture_events()
69+
70+
try:
71+
1 / 0
72+
except ZeroDivisionError:
73+
ev, _hint = event_from_exception(sys.exc_info())
74+
75+
ev["request"] = {"headers": {"COOKIE": "secret", "ip_address": "127.0.0.1"}}
76+
77+
capture_event(ev)
78+
79+
(event,) = events
80+
81+
assert event["request"] == {
82+
"headers": {"COOKIE": "[Filtered]", "ip_address": "127.0.0.1"}
83+
}
84+
85+
assert event["_meta"]["request"] == {
86+
"headers": {
87+
"COOKIE": {"": {"rem": [["!config", "s"]]}},
88+
}
89+
}
90+
91+
6392
def test_stack_var_scrubbing(sentry_init, capture_events):
6493
sentry_init()
6594
events = capture_events()
@@ -131,11 +160,16 @@ def test_span_data_scrubbing(sentry_init, capture_events):
131160

132161

133162
def test_custom_denylist(sentry_init, capture_events):
134-
sentry_init(event_scrubber=EventScrubber(denylist=["my_sensitive_var"]))
163+
sentry_init(
164+
event_scrubber=EventScrubber(
165+
denylist=["my_sensitive_var"], pii_denylist=["my_pii_var"]
166+
)
167+
)
135168
events = capture_events()
136169

137170
try:
138171
my_sensitive_var = "secret" # noqa
172+
my_pii_var = "jane.doe" # noqa
139173
safe = "keepthis" # noqa
140174
1 / 0
141175
except ZeroDivisionError:
@@ -146,13 +180,15 @@ def test_custom_denylist(sentry_init, capture_events):
146180
frames = event["exception"]["values"][0]["stacktrace"]["frames"]
147181
(frame,) = frames
148182
assert frame["vars"]["my_sensitive_var"] == "[Filtered]"
183+
assert frame["vars"]["my_pii_var"] == "[Filtered]"
149184
assert frame["vars"]["safe"] == "'keepthis'"
150185

151186
meta = event["_meta"]["exception"]["values"]["0"]["stacktrace"]["frames"]["0"][
152187
"vars"
153188
]
154189
assert meta == {
155190
"my_sensitive_var": {"": {"rem": [["!config", "s"]]}},
191+
"my_pii_var": {"": {"rem": [["!config", "s"]]}},
156192
}
157193

158194

0 commit comments

Comments
 (0)