diff --git a/sentry_sdk/scrubber.py b/sentry_sdk/scrubber.py index f863092108..c91b6b3b89 100644 --- a/sentry_sdk/scrubber.py +++ b/sentry_sdk/scrubber.py @@ -66,6 +66,7 @@ def __init__( recursive: bool = False, send_default_pii: bool = False, pii_denylist: "Optional[List[str]]" = None, + remove_user_ip_address: bool = False, ) -> None: """ A scrubber that goes through the event payload and removes sensitive data configured through denylists. @@ -74,6 +75,7 @@ def __init__( :param recursive: Whether to scrub the event payload recursively, default False. :param send_default_pii: Whether pii is sending is on, pii fields are not scrubbed. :param pii_denylist: The denylist to use for scrubbing when pii is not sent, defaults to DEFAULT_PII_DENYLIST. + :param remove_user_ip_address: Whether to remove ``user.ip_address`` instead of replacing it with ``[Filtered]``. """ self.denylist = DEFAULT_DENYLIST.copy() if denylist is None else denylist @@ -85,6 +87,7 @@ def __init__( self.denylist = [x.lower() for x in self.denylist] self.recursive = recursive + self.remove_user_ip_address = remove_user_ip_address def scrub_list(self, lst: object) -> None: """ @@ -137,7 +140,14 @@ def scrub_extra(self, event: "Event") -> None: def scrub_user(self, event: "Event") -> None: with capture_internal_exceptions(): if "user" in event: - self.scrub_dict(event["user"]) + user = event["user"] + if ( + self.remove_user_ip_address + and "ip_address" in self.denylist + and isinstance(user, dict) + ): + user.pop("ip_address", None) + self.scrub_dict(user) def scrub_breadcrumbs(self, event: "Event") -> None: with capture_internal_exceptions(): diff --git a/tests/test_scrubber.py b/tests/test_scrubber.py index 2cc5f4139f..2cacefb148 100644 --- a/tests/test_scrubber.py +++ b/tests/test_scrubber.py @@ -89,6 +89,42 @@ def test_ip_address_not_scrubbed_when_pii_enabled(sentry_init, capture_events): } +def test_user_ip_address_scrubbed_when_pii_disabled(sentry_init, capture_events): + sentry_init() + events = capture_events() + + try: + 1 / 0 + except ZeroDivisionError: + ev, _hint = event_from_exception(sys.exc_info()) + ev["user"] = {"id": "42", "ip_address": "127.0.0.1"} + + capture_event(ev) + + (event,) = events + + assert event["user"] == {"id": "42", "ip_address": "[Filtered]"} + assert event["_meta"]["user"] == {"ip_address": {"": {"rem": [["!config", "s"]]}}} + + +def test_user_ip_address_removed_when_configured(sentry_init, capture_events): + sentry_init(event_scrubber=EventScrubber(remove_user_ip_address=True)) + events = capture_events() + + try: + 1 / 0 + except ZeroDivisionError: + ev, _hint = event_from_exception(sys.exc_info()) + ev["user"] = {"id": "42", "ip_address": "127.0.0.1"} + + capture_event(ev) + + (event,) = events + + assert event["user"] == {"id": "42"} + assert "user" not in event.get("_meta", {}) + + def test_stack_var_scrubbing(sentry_init, capture_events): sentry_init() events = capture_events()