Skip to content

feat: filter username and password in URLs #864

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@
- feat(log): support kv feature of log (#851) by @lcian
- Attributes added to a `log` record using the `kv` feature are now recorded as attributes on the log sent to Sentry.

### Behavioral changes

- feat: filter username and password in URLs ([#864](https://github.com/getsentry/sentry-rust/pull/864)) by @lcian
- Usernames and passwords that could be contained in URLs captured when using the Actix Web or axum integration are now always filtered out.
- If the `Request` is created manually by the user, then these fields are not filtered out.
- This information was already filtered by Relay, but should also be filtered by the SDK itself as a first line of defense.

### Fixes

- docs: match description of `debug` option with behavior since PR #820 ([#860](https://github.com/getsentry/sentry-rust/pull/860)) by @AlexTMjugador
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions sentry-actix/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ use futures_util::future::{ok, Future, Ready};
use futures_util::{FutureExt as _, TryStreamExt as _};

use sentry_core::protocol::{self, ClientSdkPackage, Event, Request};
use sentry_core::utils::is_sensitive_header;
use sentry_core::utils::{is_sensitive_header, scrub_pii_from_url};
use sentry_core::MaxRequestBodySize;
use sentry_core::{Hub, SentryFutureExt};

Expand Down Expand Up @@ -428,7 +428,8 @@ fn sentry_request_from_http(request: &ServiceRequest, with_pii: bool) -> Request
request.uri()
)
.parse()
.ok(),
.ok()
.map(scrub_pii_from_url),
method: Some(request.method().to_string()),
headers: request
.headers()
Expand Down
1 change: 1 addition & 0 deletions sentry-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ rand = { version = "0.9.0", optional = true }
sentry-types = { version = "0.41.0", path = "../sentry-types" }
serde = { version = "1.0.104", features = ["derive"] }
serde_json = { version = "1.0.46" }
url = { version = "2.1.1" }
uuid = { version = "1.0.0", features = ["v4", "serde"], optional = true }

[dev-dependencies]
Expand Down
15 changes: 15 additions & 0 deletions sentry-core/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,23 @@ const SENSITIVE_HEADERS_UPPERCASE: &[&str] = &[
"X_API_KEY",
];

const PII_REPLACEMENT: &str = "[Filtered]";

/// Determines if the HTTP header with the given name shall be considered as potentially carrying
/// sensitive data.
pub fn is_sensitive_header(name: &str) -> bool {
SENSITIVE_HEADERS_UPPERCASE.contains(&name.to_ascii_uppercase().replace("-", "_").as_str())
}

/// Scrub PII (username and password) from the given URL.
pub fn scrub_pii_from_url(mut url: url::Url) -> url::Url {
// the set calls will fail and return an error if the URL is relative
// in those cases, just ignore the errors
if !url.username().is_empty() {
let _ = url.set_username(PII_REPLACEMENT);
}
if url.password().is_some() {
let _ = url.set_password(Some(PII_REPLACEMENT));
Comment on lines +26 to +29
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cases in which these can fail are documented as follows:

If this URL is cannot-be-a-base or does not have a host, do nothing and return `Err`.

This happens for instance if the URL is relative. In these cases we just ignore the errors.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add this information as a code comment, as it could be helpful for future developers

}
url
}
4 changes: 2 additions & 2 deletions sentry-tower/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::task::{Context, Poll};

use http::{header, uri, Request, Response, StatusCode};
use pin_project::pinned_drop;
use sentry_core::utils::is_sensitive_header;
use sentry_core::utils::{is_sensitive_header, scrub_pii_from_url};
use sentry_core::{protocol, Hub};
use tower_layer::Layer;
use tower_service::Service;
Expand Down Expand Up @@ -187,7 +187,7 @@ where
fn call(&mut self, request: Request<ReqBody>) -> Self::Future {
let sentry_req = sentry_core::protocol::Request {
method: Some(request.method().to_string()),
url: get_url_from_request(&request),
url: get_url_from_request(&request).map(scrub_pii_from_url),
headers: request
.headers()
.into_iter()
Expand Down
Loading