Skip to content

Default EventScrubber uses recursive=False, so nested denylist keys are not scrubbed | #7620

Description

@tiagovilasboas

Static review of public source at commit 85e7ce66fcca. No traffic was sent to any Sentry environment.

EventScrubber only walks nested dict/list values when recursive=True, and that flag defaults to False:

sentry_sdk/scrubber.py:

class EventScrubber:
    def __init__(
        self,
        denylist: "Optional[List[str]]" = None,
        recursive: bool = False,
        ...
    ) -> None:

if isinstance(k, str) and k.lower() in self.denylist:
    d[k] = AnnotatedValue.substituted_because_contains_sensitive_data()
elif self.recursive:
    self.scrub_dict(v)
    self.scrub_list(v)

The default client wires a scrubber without enabling recursion:

sentry_sdk/client.py:

rv["event_scrubber"] = EventScrubber(
    send_default_pii=False
    if rv["send_default_pii"] is None
    else rv["send_default_pii"]
)

Top-level keys such as authorization are scrubbed; the same key nested under extra, request.data, or breadcrumb data is not. Integrators who assume “Sentry scrubs secrets by default” get shallow coverage only.

Suggested change:

  • Default recursive=True on EventScrubber, or pass recursive=True from the client bootstrap.
  • If recursion cost is the concern, recurse only into known containers (extra, request.data, breadcrumb data, frame vars) rather than the whole event.
  • Document the flag next to send_default_pii in the scrubbing guide.

Severity: low–medium data-protection hardening (secret leakage via nested event fields). No proof-of-concept; no events were submitted.

Happy to send a focused PR + regression test with a nested denylist key if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions