Scrubbing Sensitive Data
Learn about filtering or scrubbing sensitive data within the SDK, so that data is not sent with the event. You can also configure server-side scrubbing to ensure the data is not stored.
As with any third-party service it's important to understand what data is being sent to Sentry, and where relevant ensure sensitive data either never reaches the Sentry servers, or at the very least it doesn’t get stored.
These are some great examples for data scrubbing that every company should think about:
- PII (Personally Identifiable Information) such as a user's name or email address, which post-GDPR should be on every company's mind.
- Authentication credentials, like your AWS password or key.
- Confidential IP (Intellectual Property), such as your favorite color, or your upcoming plans for world domination.
We offer the following options depending on your legal and operational needs:
- filtering or scrubbing sensitive data within the SDK, so that data is not sent to Sentry. Different SDKs have different capabilities, and configuration changes require a redeployment of your application.
- configuring server-side scrubbing to ensure Sentry does not store data. Configuration changes are done in the Sentry UI and apply immediately for new events.
- running a local Relay on your own server between the SDK and Sentry, so that data is not sent to Sentry while configuration can still be applied without deploying.
Ensure that your team is aware of your company's policy around what can and cannot be sent to Sentry. We recommend determining this policy early in your implementation and communicating it as well as enforcing it via code review.
If you are using Sentry in your mobile app, read our frequently asked questions about mobile data privacy to assist with Apple App Store and Google Play app privacy details.
If you do not wish to use the default PII behavior, you can also choose to identify users in a more controlled manner, using our user identity context.
SDKs provide a before_send
hook, which is invoked before an error or message event is sent and can be used to modify event data to remove sensitive information. Some SDKs also provide a before_send_transaction
hook which does the same thing for transactions. We recommend using before_send
and before_send_transaction
in the SDKs to scrub any data before it is sent, to ensure that sensitive data never leaves the local environment.
#include <sentry.h>
sentry_value_t strip_sensitive_data(sentry_value_t event, void *hint) {
/* modify event here or return NULL to discard the event */
return event;
}
int main(void) {
sentry_options_t *options = sentry_options_new();
sentry_options_set_before_send(options, strip_sensitive_data, NULL);
sentry_init(options);
/* ... */
}
The callback is executed in the same thread as the call to sentry_capture_event
. Work performed by the function may thus block the executing thread. For this reason, consider avoiding heavy work in before_send
.
The before_send
callback implementation in sentry-native
makes it hard to distinguish between normal events and crashes. For this reason, we introduced another callback, on_crash
, which - at this point - only exists in sentry_native
:
#include <sentry.h>
static sentry_value_t
crash_cleanup(
const sentry_ucontext_t *uctx, // provides the user-space context of the crash
sentry_value_t event, // used the same way as in `before_send`
void *closure // user-data that you can provide at configuration time
)
{
// Do contextual clean-up before the crash is sent to sentry's backend infrastructure
/* ... */
// tell the backend to retain the event (+ dump)
// or to discard it, you could free the event and return a `null`:
// sentry_value_decref(event);
// return sentry_value_new_null();
return event;
}
int main(void) {
sentry_options_t *options = sentry_options_new();
sentry_options_set_on_crash(options, crash_cleanup, NULL);
sentry_init(options);
/* ... */
}
The on_crash
callback replaces before_send
as a callback for crash events only. They can be defined simultaneously, where the SDK prevents before_send
from being invoked for crash events. This allows for better differentiation between crashes and other events and gradual migration from existing before_send
implementations:
- If you have a
before_send
implementation and do not define anon_crash
callbackbefore_send
will receive both normal and crash events as before - If you only want to pre-process normal events with
before_send
, then you can define an "empty"on_crash
callback that returns the passed-in event and does nothing else. - If you are not interested in pre-processing normal events but only want to act on crashes, then only define an
on_crash
callback with the option to filter (available for all backends) or enrich (only forinproc
) the crash event.
Not Supported in Crashpad on macOS
The Crashpad backend on macOS doesn't currently support notifying the crashing process and thus can't correctly terminate sessions or call the registered before_send
or on_crash
hooks. It will also lose any events queued for sending at the time of the crash.
Limitations in Crashpad on Windows for Fast-fail Crashes
The Crashpad backend on Windows supports fast-fail crashes, which bypass SEH (Structured Exception Handling) primarily for security reasons. sentry-native
registers a WER (Windows Error Reporting) module, which signals the crashpad_handler
to send a minidump when a fast-fail crash occurs. However, since this process bypasses SEH, the application local exception handler is no longer invoked, which also means that for these kinds of crashes, before_send
and on_crash
will not be invoked before sending the minidump and thus have no effect.
Sensitive data may appear in the following areas:
- Stack-locals → Some SDKs (Python, PHP and Node) will pick up variable values within the stack trace. These can be scrubbed, or this behavior can be disabled altogether if necessary.
- Breadcrumbs → Some SDKs (JavaScript and the Java logging integrations, for example) will pick up previously executed log statements. Do not log PII if using this feature and including log statements as breadcrumbs in the event. Some backend SDKs will also record database queries, which may need to be scrubbed.
- User context → Automated behavior is controlled via
send_default_pii
. - HTTP context → Query strings may be picked up in some frameworks as part of the HTTP request context.
- Transaction Names → In certain situations, transaction names might contain sensitive data. For example, a browser's pageload transaction might have a raw URL like
/users/1234/details
as its name (where1234
is a user id, which may be considered PII). In most cases, our SDKs can parameterize URLs and routes successfully, that is, turn/users/1234/details
into/users/:userid/details
. However, depending on the framework, your routing configuration, race conditions, and a few other factors, the SDKs might not be able to completely parameterize all of your URLs.
For more details and data filtering instructions, see Filtering Events.
Contextual information
Instead of sending confidential information in plaintext, consider hashing it:
The Native SDK maintains all data in a single global scope.
#include <sentry.h>
sentry_set_tag("birthday", checksum_or_hash("08/12/1990"));
This will allow you to correlate it within internal systems if needed, but keep it confidential from Sentry.
User details
Your organization may determine that emails are not considered confidential, but if they are, consider instead sending your internal identifier:
The Native SDK maintains all data in a single global scope.
#include <sentry.h>
sentry_value_t user = sentry_value_new_object();
sentry_value_set_by_key(user, "id", sentry_value_new_int32(client_user->id));
// OR
sentry_value_set_by_key(user, "username", sentry_value_new_string(client_user->username));
sentry_set_user(user);
Doing this will ensure you still benefit from user-impact related features.
Logging integrations
As a best practice you should always avoid logging confidential information. If you have legacy systems you need to work around, consider the following:
- Anonymize the confidential information within the log statements (for example, swap out email addresses -> for internal identifiers)
- Use
before_breadcrumb
to filter it out from breadcrumbs before it is attached - Disable logging breadcrumb integration (for example, as described here)
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").