-
-
Notifications
You must be signed in to change notification settings - Fork 368
Description
Description
While rewriting our masking tests in #6292 I noticed that text and image masking is pretty badly broken on iOS 26 when using SwiftUI standard components Text
, Label
, Image
and List
.
It seems these views are not backed by the same drawing layers as before, therefore our SDK does not detect the views as sensitive and doesn't apply masking to them.
Example for SwiftUI.Image
using an UIImage
:
let image = UIGraphicsImageRenderer(size: CGSize(width: 40, height: 40)).image { context in
UIColor.green.setFill()
context.fill(CGRect(x: 0, y: 0, width: 20, height: 20))
UIColor.purple.setFill()
context.fill(CGRect(x: 20, y: 0, width: 20, height: 20))
UIColor.blue.setFill()
context.fill(CGRect(x: 0, y: 20, width: 20, height: 20))
UIColor.orange.setFill()
context.fill(CGRect(x: 20, y: 20, width: 20, height: 20))
}
let view = VStack {
Image(uiImage: image)
}
Example of SwiftUI.Text
:
let view = VStack {
VStack {
Text("Hello SwiftUI")
.padding(20)
}
.background(Color.green)
.font(.system(size: 20)) // Use a fixed font size as defaults could change frame
}
Before masking - iOS 18.6:

After masking - iOS 18.6:

Before masking - iOS 26.0:

After masking - iOS 26.0:

Example of SwiftUI.Label
(which is basically a combination of Text
and Image
):
let view = VStack {
Label("Hello SwiftUI", systemImage: "house")
.labelStyle(.titleAndIcon)
}
Before masking - iOS 18.6:

After masking - iOS 18.6:

Before masking - iOS 26.0:

After masking - iOS 26.0:

Example of SwiftUI.List
:
let view = VStack {
List {
Section("Section 1") {
Text("Item 1")
}
Section {
Text("Item 2")
}
}
}
Before masking - iOS 18.6:

After masking - iOS 18.6:

Before masking - iOS 26.0:

After masking - iOS 26.0:

Steps to reproduce
Run the sample project iOS-SwiftUI
at version 8.56.2
using Xcode 26 and run it on iOS 26. Then take a look at the recorded session replay:
Before masking - iOS 18.6:

After masking - iOS 18.6:

Before masking - iOS 26.0:

After masking - iOS 26.0:

Details
This is from testing with Flinky:
- ✅ Build with Xcode 16.4, running on iOS 18.6 → text is masked
- ✅ Build with Xcode 16.4, running on iOS 26.0 → text is masked (not Liquid Glass)
- ✅ Build with Xcode 26, running on iOS 18.6 → text is masked
- 🔥 Build with Xcode 26, running on iOS 26.0 → text is unmasked (Liquid Glass)
Ignore the unmasked top area, that's due to a geometry error.
Additonal Context
Using the debug command (lldb) po view.value(forKey: "recursiveDescription")!
it is possible to investigate the underlying view hierarchy. This can also be used to see how standard UIKit components like UISlider
is implemented per iOS version:

Next Steps
- As a defensive strategy we disable session replay by default unless we detect none of the indicators (running on iOS 26.0, build with Xcode 26.0, using Liquid Glass) --> fix(session-replay): Add detection for potential PII leaks disabling session replay #6389
- Add tests for all supported iOS versions and UI components --> fix(session-replay): Extend masking and focus masking on sensitive information #6292
- Fix masking on iOS 26.0 using SwiftUI / Liquid Glass
- Mark option introduced in fix(session-replay): Add detection for potential PII leaks disabling session replay #6389 as deprecated