View Source Sentry.Scrubber (Sentry v13.2.0)
Shared, framework-agnostic helpers for scrubbing sensitive data before it is sent to Sentry.
Available since v13.1.0.
This module owns the default sensitive key lists, the placeholder used in
place of redacted values, the credit-card detection heuristic, and the
recursive map/list traversal used by the rest of the SDK to redact values.
Integrations such as Sentry.PlugContext, Sentry.PlugCapture, and
Sentry.LiveViewHook delegate to the functions exposed here so that
scrubbing rules live in a single place.
Defaults
The default sensitive parameter keys (used for body params, query strings, and arbitrary maps) are:
"password""passwd""secret"
The default sensitive header keys are:
"authorization""authentication""cookie"
Values matching a credit-card-like pattern (13–16 digits, optionally separated by spaces or dashes) are also replaced with the placeholder.
Custom scrubbing
The map/query/header functions accept an optional :keys option that
overrides the default list of sensitive keys. This makes it possible to
compose custom scrubbers on top of the defaults:
def scrub(map) do
map
|> Sentry.Scrubber.scrub(keys: ["password", "api_key"])
|> Map.drop(["internal_notes"])
end
Scrubbing a %Plug.Conn{}
scrub/1 redacts a conn by applying, to each field listed in the
@scrubbable_conn_fields attribute, that field's strategy. A strategy is
either:
- a configurable scrubber (
:cookie_scrubber,:header_scrubber,:body_scrubber) — resolved per process viaput_conn_scrubber/1(typically fromSentry.PlugContext.call/2), falling back to the SDK defaultscrub(conn, field)clause when none is registered, or - a fixed tag —
:clearreplaces the field with%{},:paramsscrubs the field as a params-shaped map,:query_stringredacts sensitive params from a raw query string, and:private_allow_listkeeps only the registered allow-listed keys of the field (seedefault_private_allow_list/0and the:private_allow_listoption ofput_conn_scrubber/1), dropping everything else.
By default scrub/1 redacts cookies, req_headers, params, and
body_params (the configurable fields — body_params shares the
:body_scrubber with params, so it honors the same registered scrubber and
is emptied when body_scrubber is nil), clears req_cookies and assigns
to %{}, scrubs query_params as a params-shaped map, and reduces private
to its allow-listed keys (default_private_allow_list/0). assigns is cleared
wholesale because auth libraries (Guardian, Pow, Coherence) routinely store
decoded tokens, full user structs, and session data there, where no key-based
heuristic redacts safely. private keeps only the allow-listed framework
metadata and drops everything else (notably :plug_session).
The defaults can be overridden per call with scrub(conn, overrides), where
overrides is a field: strategy keyword list merged over the attribute —
for example scrub(conn, assigns: :clear). The request URL is not a conn
field, so callers fetch the registered :url_scrubber with get/1 and apply
it to the conn.
Summary
Types
Options accepted by put_conn_scrubber/1.
A per-field scrubber identifying how to redact a particular %Plug.Conn{}
field.
Options accepted by the scrubbing functions in this module.
A resolved set of per-field scrubbers for a %Plug.Conn{}.
Functions
Returns the default list of sensitive header keys.
Returns the default list of sensitive parameter keys.
Returns the default list of %Plug.Conn{} :private keys retained by the
:private_allow_list scrubbing strategy.
Drops sensitive keys from a flat map.
Returns the current process's resolved scrubber function for the given field.
Builds a resolved t/0 set of per-field scrubbers from the given options.
Registers the current process's per-field scrubbers for %Plug.Conn{}.
Scrubs a %Plug.Conn{} or a plain map.
Scrubs a value with the given options, dispatching on the value's type.
Scrubs an application/x-www-form-urlencoded query string, replacing the
value of any sensitive parameter with the placeholder.
Scrubs the query string portion of a URL, replacing the value of any sensitive query parameter with the placeholder. URLs without a query string are returned unchanged.
The placeholder string used to replace scrubbed values.
Types
@type conn_scrubber_opts() :: [ body_scrubber: field_scrubber(), header_scrubber: field_scrubber(), cookie_scrubber: field_scrubber(), url_scrubber: field_scrubber(), private_allow_list: [atom()] ]
Options accepted by put_conn_scrubber/1.
Each *_scrubber key, when omitted, falls back to the field's default
scrubber — the matching scrub(conn, field) clause of scrub/2.
:private_allow_list defaults to default_private_allow_list/0.
@type field_scrubber() :: (Plug.Conn.t() -> term()) | {module(), atom()} | nil
A per-field scrubber identifying how to redact a particular %Plug.Conn{}
field.
- a 1-arity function — invoked as
fun.(conn) {module, function}— invoked asapply(module, function, [conn])nil— disables the scrubber; map-shaped fields are replaced with%{}, and:urlfalls back to the request URL unchanged
@type option() :: {:keys, [String.t()]}
Options accepted by the scrubbing functions in this module.
@type t() :: %Sentry.Scrubber{ body_scrubber: (Plug.Conn.t() -> term()), cookie_scrubber: (Plug.Conn.t() -> term()), header_scrubber: (Plug.Conn.t() -> term()), private_allow_list: [atom()], url_scrubber: (Plug.Conn.t() -> String.t()) }
A resolved set of per-field scrubbers for a %Plug.Conn{}.
Each scrubber field holds a 1-arity function that takes the conn and returns
the scrubbed value for the corresponding field. private_allow_list holds the
keys retained by the :private_allow_list strategy. Built by
put_conn_scrubber/1 from conn_scrubber_opts/0 and stored in the process
dictionary.
Functions
@spec default_header_keys() :: [String.t()]
Returns the default list of sensitive header keys.
@spec default_param_keys() :: [String.t()]
Returns the default list of sensitive parameter keys.
@spec default_private_allow_list() :: [atom()]
Returns the default list of %Plug.Conn{} :private keys retained by the
:private_allow_list scrubbing strategy.
These are Phoenix's routing/render metadata keys, kept because they are
high-signal, non-sensitive breadcrumbs for triaging errors. This is the
default for the scrubber: [conn_private_allow_list: ...] configuration option.
Drops sensitive keys from a flat map.
This is the strategy used for HTTP headers, where the sensitive value should not appear in the payload at all.
Options
:keys- the list of sensitive keys to drop. Defaults todefault_header_keys/0.
@spec get(atom()) :: (Plug.Conn.t() -> term())
Returns the current process's resolved scrubber function for the given field.
key is one of [:body_scrubber, :header_scrubber, :cookie_scrubber, :url_scrubber]. Returns the scrubber registered
via put_conn_scrubber/1, or the field's default if none was registered. The
returned function takes a %Plug.Conn{} and returns the scrubbed value, so
callers apply it as Sentry.Scrubber.get(:url_scrubber).(conn).
@spec new(conn_scrubber_opts()) :: t()
Builds a resolved t/0 set of per-field scrubbers from the given options.
Accepts the same :body_scrubber, :header_scrubber, :cookie_scrubber,
and :url_scrubber keys as put_conn_scrubber/1. Each missing key falls
back to the field's default scrubber (the matching scrub(conn, field)
clause). Called with no arguments, new/0 returns the all-defaults scrubber.
Unlike put_conn_scrubber/1, this only constructs the struct — it does not
register it for the current process.
@spec put_conn_scrubber(conn_scrubber_opts()) :: :ok
Registers the current process's per-field scrubbers for %Plug.Conn{}.
Accepts the same :body_scrubber, :header_scrubber, :cookie_scrubber,
and :url_scrubber keys that Sentry.PlugContext takes as plug options,
resolves each missing key to the field's default scrubber (the
{__MODULE__, :scrub, [field]} MFA, i.e. the matching scrub(conn, field)
clause), and stores the resolved scrubbers in the process dictionary.
The registration lives for the lifetime of the calling process — typically
the request process when registered from Sentry.PlugContext.call/2. Used
by other parts of the SDK (notably Sentry.PlugCapture) so all conn
scrubbing honors the same configuration the user passed to
plug Sentry.PlugContext.
Returns :ok.
@spec scrub(Plug.Conn.t()) :: Plug.Conn.t()
@spec scrub(map()) :: map()
@spec scrub(term()) :: term()
Scrubs a %Plug.Conn{} or a plain map.
Given a %Plug.Conn{}, scrubs each field listed in @scrubbable_conn_fields
according to its strategy — see the "Scrubbing a %Plug.Conn{}" section in
the module docs and scrub/2 for the per-field defaults and how to override
them per call. The request URL is not a conn field; callers scrub it
separately by applying the :url_scrubber from get/1 (whose default is
scrub(conn, :url)).
Given a plain map, recursively scrubs it with the default sensitive keys —
equivalent to scrub(map, []). Any other struct is converted to a map and
scrubbed the same way, so a sensitive field can't slip through unredacted —
for example when the struct is inspected into stacktrace frame vars. See
scrub/2.
@spec scrub(map(), [option()]) :: map()
@spec scrub(list(), [option()]) :: list()
@spec scrub(term(), [option()]) :: term()
@spec scrub( Plug.Conn.t(), keyword() ) :: Plug.Conn.t()
@spec scrub(Plug.Conn.t(), :body | :headers | :cookies | :url) :: term()
Scrubs a value with the given options, dispatching on the value's type.
Scrubbing a map, list, or leaf value — scrub(value, opts)
Recursively scrubs a map: any value whose key is in the configured sensitive key list is replaced with the placeholder, and the remaining values are scrubbed in turn. Lists are scrubbed element-wise, structs are scrubbed as maps, and credit-card-shaped binaries are replaced with the placeholder. Any other leaf value is returned unchanged.
Accepts the same :keys option as the other scrubbing functions:
:keys- the list of sensitive keys to redact. Defaults todefault_param_keys/0.
Scrubbing a single %Plug.Conn{} field — scrub(conn, field)
Extracts the given field from the conn and applies the SDK's default
redaction for it. Each clause is what the field's default scrubber captures
as a {__MODULE__, :scrub, [field]} MFA, and what scrub/1 (conn fields)
and get/1 (URL) fall back to when no custom scrubber is registered:
:body— scrubsconn.paramsviascrub/2; non-map params (such as%Plug.Conn.Unfetched{}) pass through unchanged.:headers— drops sensitiveconn.req_headerscase-insensitively, preserving the list-of-tuples shape.:cookies— drops all cookies, returning%{}.:url— scrubs sensitive query parameters from the request URL viascrub_url/1. To disable URL scrubbing, register a:url_scrubberofnil(or a custom one); seeSentry.PlugContext.
Because these clauses are the defaults (not the registered scrubbers), a
custom :body_scrubber can safely compose on the default behavior without
recursing:
defmodule MyScrubber do
def scrub_params(conn) do
conn
|> Sentry.Scrubber.scrub(:body)
|> Map.drop(["my_secret_field"])
end
end
Scrubbing a whole %Plug.Conn{} with overrides — scrub(conn, overrides)
Behaves like scrub/1 but merges the field: strategy keyword overrides
over the @scrubbable_conn_fields defaults, so a caller can scrub additional
fields or change a field's strategy for that call. Strategies are a
configurable scrubber struct-key, :clear (replace with %{}), or :params
(params-shaped scrub of that field):
Sentry.Scrubber.scrub(conn, assigns: :clear, query_params: :params)
Scrubs an application/x-www-form-urlencoded query string, replacing the
value of any sensitive parameter with the placeholder.
Options
See scrub/2.
Scrubs the query string portion of a URL, replacing the value of any sensitive query parameter with the placeholder. URLs without a query string are returned unchanged.
Options
See scrub/2.
@spec scrubbed_value() :: String.t()
The placeholder string used to replace scrubbed values.