fix(replay): Stop network detail capture leaking into non-replay events - #3947
fix(replay): Stop network detail capture leaking into non-replay events#3947hkarmoush wants to merge 1 commit into
Conversation
Session Replay's opt-in HTTP body/header capture attached its data to the shared http breadcrumb, which then rode along into every subsequent Dart-captured error/transaction event and, on Android, into native crash events too - not just replay recordings (getsentry#3900). Request/response detail is now delivered via a Hint instead of breadcrumb.data, so it's never stored on the Scope. On Android it reaches the replay breadcrumb converter through a new side channel (ReplayNetworkDetailCache, correlated by an opaque replay_request_id) that never touches native Scope, closing the crash-event leak without touching the shipped Android replay rendering. iOS/FFI/Web never see the detail at all now, closing a zero-benefit leak there too (iOS doesn't render it in replay). Note: the Kotlin/Android native changes, including a hand-authored addition to the auto-generated JNI bindings in lib/src/native/java/binding.dart, could not be compiled or tested in this environment (no Android SDK/JDK/cmake available). They mirror existing generated/native patterns exactly but need verification via scripts/generate-jni-bindings.sh and a real device/emulator run before this is considered ready to ship. Co-Authored-By: Claude <noreply@anthropic.com>
82d256d to
4b9f2f6
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ 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 4b9f2f6. Configure here.
| replayRequestId, | ||
| request: request is Map<String, dynamic> ? request : null, | ||
| response: response is Map<String, dynamic> ? response : null, | ||
| ); |
There was a problem hiding this comment.
Network details race with native breadcrumbs
Medium Severity
The native http breadcrumb is written to Android Scope before ReplayNetworkDetailCache is populated, and conversion consumes the entry. If replay builds a segment in that gap, replay_request_id is present but request/response headers and bodies never attach, so Session Replay can drop the detail this change is meant to preserve.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 4b9f2f6. Configure here.
| FutureOr<void> removeContexts(String key); | ||
| FutureOr<void> setUser(SentryUser? user); | ||
| FutureOr<void> addBreadcrumb(Breadcrumb breadcrumb); | ||
| FutureOr<void> addBreadcrumb(Breadcrumb breadcrumb, Hint hint); |
There was a problem hiding this comment.
ScopeObserver signature is a breaking change
Medium Severity
Public ScopeObserver.addBreadcrumb now requires a Hint argument, so existing implementors outside this repo no longer compile. That is a breaking public-API change without deprecation or migration notes, which the PR review guidelines require flagging, and it conflicts with the PR’s “No breaking changes” claim.
Triggered by project rule: PR Review Guidelines for Cursor Bot (Root)
Reviewed by Cursor Bugbot for commit 4b9f2f6. Configure here.


📜 Description
Session Replay's opt-in HTTP body/header capture attached its data to the shared HTTP breadcrumb, which then rode along into every subsequent Dart-captured error/transaction event and, on Android, into native crash events too — not just replay recordings.
Request/response detail is now delivered via a
Hintinstead ofbreadcrumb.data, so it's never stored on theScope. On Android it reaches the replay breadcrumb converter through a new side channel (ReplayNetworkDetailCache, correlated by an opaquereplay_request_id) that never touches the nativeScope, closing the crash-event leak without touching the shipped Android replay rendering. iOS/FFI/Web never see the detail at all now, closing a zero-benefit leak there too (iOS doesn't render it in replay).💡 Motivation and Context
Fixes #3900.
💚 How did you test it?
BreadcrumbClient,Scope,NativeScopeObserver, andMockScopeObservercovering the newHint-based path.lib/src/native/java/binding.dart. The changes mirror existing generated/native patterns exactly but need verification viascripts/generate-jni-bindings.shregeneration and a real device/emulator run before this is ready to ship — opening as a draft until that's done.📝 Checklist
sendDefaultPiiis enabled🔮 Next steps
scripts/generate-jni-bindings.shand confirm on a real Android device/emulator.🤖 Generated with Claude Code