iOS security and privacy
The Surface Security iOS app is designed to resist accidental (and casual intentional) data leakage of alert content. This page describes what's protected, how, and what's explicitly not protected so you can set realistic expectations.
Protections at a glance
| Protection | How |
|---|---|
| Face ID / passcode on every app open | LocalAuthentication evaluates the device-owner policy on every .active transition. No grace period. |
| Screenshots blocked | Content is rendered inside a secure-entry UITextField layer — screenshots capture black. |
| Screen recording blocked | Same secure-entry layer blanks recordings; a banner also warns the user. |
| Copy/paste disabled on alert content | SwiftUI Text is non-selectable by default; SecureTextView overrides every UIKit callout. |
| Pasteboard cleared on backgrounding | UIPasteboard.general.items = [] every time the app backgrounds. |
| App-switcher preview hidden | An opaque logo view is attached before iOS snaps the preview. |
| Tokens stored on-device only | Keychain with kSecAttrAccessibleWhenUnlockedThisDeviceOnly — cannot be iCloud-backed-up. |
| Remote sign-out | Admins can revoke a device via the dashboard — next push is refused. |
Not protected
Be realistic about the ceiling of what iOS alone can enforce:
- Jailbroken devices. All of the above protections can be bypassed on a jailbroken phone. We do not attempt to detect jailbreak — the detection arms race is expensive and unreliable, and any organization requiring this protection should enforce it at the MDM layer (e.g. require a managed device, forbid jailbreak via compliance policy).
- Photographing the screen. Nothing a software app can do prevents a second phone photographing the display. The screenshot and recording protections close the easy vectors, not this one.
- Visual recall / OCR. If a user sees an alert, they can remember and retype facts elsewhere. These protections stop data export, not human recall.
What we store on-device
The Keychain stores:
accessToken(JWT, 24-hour lifetime)refreshToken(longer-lived)serverURL,tenantSlug,tenantID,deviceID
That is all. No alert bodies, screenshots, or user PII are cached to disk outside of normal in-memory rendering. Closing the app purges the render state.
Biometric policy
The gate uses LAPolicy.deviceOwnerAuthentication which:
- Prefers Face ID / Touch ID if enrolled.
- Falls back to the device passcode if biometrics fail or aren't enrolled.
- Allows up to the OS's configured retries (typically 5) before requiring passcode.
Cancelling the prompt leaves the app locked — there is no way to see alert content without unlocking.
Reporting a suspected breach
If you suspect a device has been compromised:
- Have the user sign out from the app if possible.
- On the web, revoke their device(s) from the Admin users page.
- Rotate their password / expire their SSO session.
- Review the
ios_screenshot_attemptevents in the audit log for anomalous activity.