feat(tower): Capture client IP addresses - #1274
Conversation
Populate REMOTE_ADDR from X-Forwarded-For, X-Real-IP, or request socket extensions when PII collection is enabled. Keep the address out of captured requests when PII is disabled. Closes getsentry#769
|
👋 Thanks for sending this our way! Before a maintainer reviews the code, we ask community contributors to align with us on the approach first — it keeps your time pointed at changes we can land. The easiest way is to open or find a GitHub issue and discuss the approach with a maintainer there, then link that issue from this PR. If the issue is already assigned to someone else, please check in with them (or with us) before continuing — otherwise two people may end up working on the same task. See our contributing guidelines for the full picture. |
| .and_then(|value| value.split(',').next()) | ||
| .map(str::trim) | ||
| .filter(|value| !value.is_empty()) | ||
| .or_else(|| { | ||
| request | ||
| .headers() | ||
| .get("x-real-ip") | ||
| .and_then(|value| value.to_str().ok()) | ||
| .map(str::trim) | ||
| .filter(|value| !value.is_empty()) | ||
| }) |
There was a problem hiding this comment.
Bug: The remote_addr_from_request function extracts an IP from the x-forwarded-for header without validating if the value is a syntactically correct IP address, potentially capturing and sending invalid data.
Severity: MEDIUM
Suggested Fix
Update the remote_addr_from_request function to validate that the extracted string is a valid IPv4 or IPv6 address before returning it. This can be achieved by parsing the string using a standard library function like std::net::IpAddr::from_str. This will ensure only valid IP addresses are processed.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: sentry-tower/src/http.rs#L243-L255
Potential issue: The `remote_addr_from_request` function extracts a potential IP address
from the `x-forwarded-for` header. It processes the header value but does not validate
if the resulting string is a syntactically correct IP address. The only check performed
is to ensure the string is not empty after trimming. This allows malformed values, such
as `not-an-ip`, or even malicious content to be captured and sent to Sentry as the
`REMOTE_ADDR`. While the Sentry backend may perform its own validation, this behavior
allows invalid data from an untrusted source to be processed and transmitted over the
network.
Did we get this right? 👍 / 👎 to inform future reviews.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5f80b05. Configure here.
| .extensions() | ||
| .get::<IpAddr>() | ||
| .map(ToString::to_string) | ||
| }) |
There was a problem hiding this comment.
Axum peer IP lookup fails
Medium Severity
The socket fallback looks up bare SocketAddr and IpAddr in request extensions, but axum stores the peer address as ConnectInfo<SocketAddr>. With the documented axum setup—and especially axum::serve, which provides that extension by default—the fallback never finds a client IP when proxy headers are absent, so REMOTE_ADDR is left unset.
Reviewed by Cursor Bugbot for commit 5f80b05. Configure here.


What changed
Capture
REMOTE_ADDRfrom the firstX-Forwarded-Forvalue,X-Real-IP, or the request socket extension when PII collection is enabled. Leave the address out when PII collection is disabled.Tests
cargo test -p sentry-tower --all-features --lockedcargo +1.88.0 test -p sentry-tower --all-features --lockedcargo test --workspace --all-features --all-targets --lockedcargo clippy --all-features --workspace --tests --examples --locked -- -D clippy::allCloses #769