Advanced Data Scrubbing
Learn about using Advanced Data Scrubbing as an alternative way to redact sensitive information just before it is saved in Sentry.
In addition to using hooks in your SDK or our server-side data scrubbing features to redact sensitive data, Advanced Data Scrubbing is an alternative way to redact sensitive information just before it is saved in Sentry. It allows you to:
- Define custom regular expressions to match on sensitive data
- Detailed tuning on which parts of an event to scrub
- Partial removal or hashing of sensitive data instead of deletion
Rule Precedence
Advanced Data Scrubbing rules take precedence over other Server-Side Data Scrubbing settings. Specifically, any advanced rule will apply regardless of whether the matched field is in Safe Fields or not.
Navigate to your project- or organization-settings, click Security and Privacy, then Advanced Data Scrubbing.
- Click on Add Rule. You will be presented with a new dialog.
- Select Mask as Method.
- Select Credit card numbers as Data Type.
- Enter
$string
as Source.
As soon as you press Save, Sentry will attempt to find all credit card numbers in your events going forward, and replace them with a series of ******
.
For a more verbose tutorial check out this blogpost.
Rules generally consist of three parts:
- Remove: Remove the entire field. We may choose to either set it to
null
, remove it entirely, or replace it with an empty string depending on technical constraints. - Mask: Replace all characters with
*
. - Hash: Replace the matched substring with a hashed value.
- Replace: Replace the matched substring with a constant placeholder value (defaulting to
[Filtered]
).
Regex Matches: Custom regular expression. For example:
[a-zA-Z0-9]+
. Some notes:- Do not write
/[a-zA-Z0-9]+/g
, as that will search for a literal/
and/g
. - For case-insensitivity, prefix your regex with
(?i)
. - If you're trying to use one of the popular regex "IDEs" like regex101.com, Golang is usually closest to how Sentry understands your regex.
- Escape using
\
, e.g.\*
is a literal*
. This works for any of the following characters:\.+*?()|[]{}^$
.
- Do not write
Credit Card Numbers: Any substrings that look like credit card numbers.
Password Fields: Any substrings that look like they may contain passwords. Any string that mentions passwords, auth tokens or credentials, any variable that is called
password
orauth
.IP Addresses: Any substrings that look like valid IPv4 or IPv6 addresses.
IMEI Numbers: Any substrings that look like an IMEI or IMEISV.
Email Addresses
UUIDs
PEM Keys: Any substrings that look like the content of a PEM-keyfile.
Auth in URLs: Usernames and passwords in URLs like
https://user:pass@example.com/foo
.US social security numbers: 9-digit social security numbers for the USA.
Usernames in filepaths: For example
myuser
in/Users/myuser/file.txt
,C:\Users\myuser\file.txt
,C:\Documents and Settings\myuser\file.txt
,/home/myuser/file.txt
, ...MAC Addresses
Anything: Matches any value. This is useful if you want to remove a certain JSON key by path using Sources regardless of the value.
Sentry does not know what your code does
Sentry does not know if a local variable that looks like a credit card number actually is one. As such, you need to expect not only false-positives but also false-negatives. Sources can help you in limiting the scope in which your rule runs.
Selectors allow you to restrict rules to certain parts of the event. This is useful to unconditionally remove certain data by event attribute, and can also be used to conservatively test rules on real data. A few examples:
**
to scrub all default event PII fields (other fields, like the span description, require specific selectors)$error.value
to scrub in the exception message$message
to scrub the event-level log messageextra.'My Value'
to scrub the keyMy Value
in "Additional Data"extra.**
to scrub everything in "Additional Data"$http.headers.x-custom-token
to scrub the request headerX-Custom-Token
$user.ip_address
to scrub the user's IP address$frame.vars.foo
to scrub a stack trace frame variable calledfoo
contexts.device.timezone
orcontexts.culture.timezone
to scrub a key from the Device contexttags.server_name
to scrub the tagserver_name
All key names are treated case-insensitively.
Above the Source input field you will find another input field for an event ID. Providing a value there allows for better auto-completion of arbitrary Additional Data fields and variable names.
The event ID is purely optional and the value is not saved as part of your settings. Data scrubbing settings always apply to all new events within a project/organization (going forward).
Data scrubbing always works on the raw event payload. Keep in mind that some fields in the UI may be called differently in the JSON schema. When looking at an event there should always be a link called "JSON" present that allows you to see what the data scrubber sees.
For example, what is called "Additional Data" in the UI is called extra
in the event payload. To remove a specific key called foo
, you would write:
[Remove] [Anything] from [extra.foo]
Another example. Sentry knows about two kinds of error messages: the exception message, and the top-level log message. Here is an example of how such an event payload as sent by the SDK (and downloadable from the UI) would look like:
{
"logentry": {
"formatted": "Failed to roll out the dinglebop"
},
"exception": {
"values": [
{
"type": "ZeroDivisionError",
"value": "integer division or modulo by zero"
}
]
}
}
Since the "error message" is taken from the exception
's value
, and the "message" is taken from logentry
, we would have to write the following to remove both from the event:
[Remove] [Anything] from [exception.values.*.value]
[Remove] [Anything] from [logentry.formatted]
You can combine sources using boolean logic.
- Prefix with
!
to invert the source.foo
matches the JSON keyfoo
, while!foo
matches everything butfoo
. - Build the conjunction (AND) using
&&
, such as:foo && !extra.foo
to match the keyfoo
except when inside ofextra
. - Build the disjunction (OR) using
||
, such as:foo || bar
to matchfoo
orbar
.
**
matches all subpaths, so thatfoo.**
matches all JSON keys withinfoo
.*
matches a single path item, so thatfoo.*
matches all JSON keys one level belowfoo
.
Select subsections by JSON-type using the following:
$string
: Matches any string value$number
: Matches any integer or float value$datetime
: Matches any field in the event that represents a timestamp$array
: Matches any JSON array value$object
: Matches any JSON object
Select known parts of the schema using the following:
$error
: Matches a single exception instance. Alias forexception.values.*
$stack
: Matches a stack trace instance. Alias forstacktrace || $error.stacktrace || $thread.stacktrace
$frame
: Matches a frame in a stack trace. Alias for$stacktrace.frames.*
$http
: Matches the HTTP request context of an event. Alias forrequest
$user
: Matches the user context of an event. Alias foruser
$message
: Matches the top-level log message. Alias for$logentry.formatted
$logentry
: Matches thelogentry
attribute of an event. Alias forlogentry
$thread
: Matches a single thread instance. Alias forthreads.values.*
$breadcrumb
: Matches a single breadcrumb. Alias forbreadcrumbs.values.*
$span
: Matches a trace span. Alias forspans.*
$sdk
: Matches the SDK context. Alias forsdk
Select attachment and parts of attachments, see Attachment Scrubbing for details.
$attachments
: Root selector for attachments.$minidump
: Selector for minidump attachments.$binary
: Matches all binary data fields in attachments.
If the object key you want to match contains whitespace or special characters, you can use quotes to escape it:
[Remove] [Anything] from [extra.'my special value']
This matches the key my special value
in Additional Data.
To escape '
(single quote) within the quotes, replace it with ''
(two quotes):
[Remove] [Anything] from [extra.'my special '' value']
This matches the key my special ' value
in Additional Data.
The following limitations generally apply to all server-side data scrubbing, be it basic Safe Fields usage or Advanced Data Scrubbing.
Hashing, masking or replacing a JSON object, array or number (anything that is not a string) cannot be done in all circumstances as it would change the JSON type of the value and violate assumptions Sentry's internals make about the data schema. Data scrubbing will ignore the Method in those cases and always remove/replace with
null
as that is always safe.Sentry's internals require that the event user's IP address must either be
null
or a valid IPv4/IPv6 address. If you're trying to hash, mask or replace IP addresses, data scrubbing will move the replacement value into the user ID (if one is not already set) in order to avoid breaking this requirement while still providing useful data for the Users count on an issue.In stack traces, scrubbing works on file paths but not on a file's base name. This would violate assumptions in the processing pipeline resulting in a poor user experience. Instead, you can scrub a file's base name in the SDK itself, using the
RewriteFrames
integration orbeforeSend
.
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").