auditing-ios-app-group-and-pasteboard-exposure · git:20260908.e3ae18a · 2026-09-08 · sha256 d6f060999977c8b9
auditing-ios-app-group-and-pasteboard-exposure git:20260908.e3ae18aA
Immutable. This exact content is served forever at /api/v1/blob/d6f060999977c8b9.
--- name: auditing-ios-app-group-and-pasteboard-exposure description: >- Audit sensitive data leaving an iOS app's protection through shared containers and system-wide channels, where a secret or private value is written to a shared app-group container, a shared keychain access group, the general pasteboard, or app state that lands in snapshots and extensions, so another app, an app extension, or any process reading the pasteboard can recover it, because the shared surface is broader than the data's sensitivity requires. Use when reviewing what an iOS app shares with its own extensions or other apps and what it copies or exposes system-wide. Covers app-group container leakage, over-broad shared keychain groups, general-pasteboard secrets, and snapshot or extension data exposure. The sensitive value placed on a shared surface is the source, the other app or process reading that surface is the sink, and recovering the value outside the app's boundary is the bug. license: MIT --- # Auditing iOS app group and pasteboard exposure: when a secret leaves the app through a shared door An iOS app is meant to be a sealed container, but it has several legitimate doors through which data leaves: an app-group container it shares with its own extensions, a shared keychain access group, the general pasteboard any app can read, and the state the system captures in snapshots or hands to extensions. Each door is fine for data whose sensitivity tolerates the audience on the other side, and a leak when a secret goes through a door wider than it should. A token written to an app-group container is readable by every extension and app in that group; a secret in an over-broad shared keychain group is reachable by apps that should not have it; a value copied to the general pasteboard is readable by any app, including ones the user never launched deliberately; and sensitive data left on screen or in memory lands in a snapshot or an extension context. The bug is a sensitive value on a shared surface whose audience exceeds the app's own boundary. You audit these by listing what the app writes to each shared surface and who can read it. ## When to use - An iOS app shares data with its own extensions through an app group or a shared keychain access group. - The app copies or exposes values through the general pasteboard or hands data to an extension. - Sensitive data may appear in a snapshot, a shared container, or a channel other apps can read. ## Scope check Audit shared-surface exposure only on apps and devices you own or are authorized to assess, on test devices and accounts, recovering only test data from the shared surface rather than a real user's. A confirmed leak lets another app or process read the app's private data, so keep every probe within scope. If you can't name the authorization, stop. ## The loop 1. **Establish the audience of each shared surface and the sensitivity of what is written to it first.** For each shared surface the app uses, an app-group container, a shared keychain group, the general pasteboard, a snapshot, or an extension handoff, determine who can read it and whether the data written there tolerates that audience. This is the false-positive killer: a shared surface carrying only data whose sensitivity matches its audience is not a leak, and a sensitive value never written to a shared surface is not exposed. Name the surface, its audience, and the sensitive value before claiming a leak. 2. **Enumerate the shared surfaces and their contents.** List the app-group containers, shared keychain access groups, pasteboard uses, and extension or snapshot data paths, and for each what the app writes there. Note which carry secrets, tokens, or private data. 3. **Check the app-group and shared-keychain scope.** Determine whether the app-group container or shared keychain access group is scoped only to the app and its own extensions, or is broad enough that another app can join or read it, and whether the data placed there needs to be shared at all. 4. **Check the pasteboard and snapshot exposure.** Determine whether sensitive values reach the general pasteboard, readable by any app, rather than a scoped or expiring pasteboard, and whether sensitive data left visible or in memory is captured in a snapshot or exposed to an extension that should not see it. 5. **Check whether the sharing is necessary.** Determine whether each sensitive value genuinely needs the shared surface, or whether it could stay in the app's private container or keychain scope. Data that need not be shared should not be on a shared surface at all. 6. **Confirm and record.** Confirm by recovering a sensitive test value from the shared surface as another app, an extension, or a pasteboard reader on a test device, or observing it in a snapshot. Kill the lead if every shared surface carries only data whose sensitivity matches its audience, if no secret reaches the general pasteboard or a snapshot, and if shared scopes are limited to the app and its own extensions. Record the surface, its audience, the leaked value, and the recovery, or set a `kill_reason`. ## Where shared-surface exposure leaks - **The audience of the surface is the finding.** A shared door is expected; the leak is a sensitive value whose audience on the far side exceeds the app's boundary. Name the surface and who reads it. - **App-group containers are readable by the whole group.** A token or secret written to an app-group container is available to every extension and app in that group, not just the one that wrote it. - **Over-broad shared keychain groups widen reach.** A shared keychain access group larger than the app and its own extensions lets apps that should not hold a secret read it. - **The general pasteboard is world-readable.** A value copied to the general pasteboard can be read by any app, so sensitive data belongs on a scoped or expiring pasteboard, or not copied at all. - **Snapshots and extensions capture on-screen state.** Sensitive data left visible or in memory is captured in a snapshot or handed to an extension, leaking it outside the deliberate flow. ## Worked example (a confirm and a kill) > **Confirm.** An app writes an authentication token to an app-group container so its extension can use it, > but the group is broad and the token is stored in the clear. A separate app in the group reads the token > from the shared container on a test device, recovering a usable test credential. **Confirmed** private data > exposure through an over-broad shared container, `high`, remediation = scope the app group and shared > keychain access group to the app and its own extensions only, store shared secrets bound to a key the > reader must hold, and keep values that need not be shared in the app's private container. > > **Kill.** The same app shares only a non-sensitive value through an app group scoped to the app and its own > extensions, keeps the token in its private keychain scope, never copies secrets to the general pasteboard, > and marks sensitive screens so they are excluded from snapshots. No other app or process recovers a > sensitive value. **Killed**, `kill_reason` = "shared surfaces carry only data whose audience matches its > sensitivity, the token stays in a private scope, and no secret reaches the pasteboard or a snapshot; nothing > sensitive leaves the app boundary." ## Rationalizations to reject - *"The app group is only for our own extension."* -> Confirm the group and shared keychain scope actually exclude other apps; a broad group or access group lets an app the user did not intend read the data. - *"The pasteboard is convenient for the user."* -> The general pasteboard is readable by any app; use a scoped or expiring pasteboard for sensitive values, or do not copy them at all. - *"That container is inside the sandbox."* -> A shared container is shared by design; its audience is the whole group, so sandbox membership does not make it private to one app. - *"Snapshots are internal to the OS."* -> A snapshot of a sensitive screen can be read from the device or a backup; exclude sensitive screens from capture rather than assuming the snapshot is safe. - *"The value has to be shared."* -> Confirm it does; much shared data need not be, and the fix is often to keep it in the private container rather than to widen the audience. ## Executing this in practice You need every shared surface the app uses, app-group containers, shared keychain access groups, pasteboard uses, snapshot and extension data paths, with the audience of each and what the app writes there. For each sensitive value, decide whether its surface's audience exceeds the app's boundary and whether it needs to be shared at all. Reading what is written and the scope of each surface settles most leads; recovering a sensitive test value as another app, an extension, or a pasteboard reader on a test device settles the rest. ## Related - `hunting-ios-keychain-and-data-protection-gaps` - a secret that leaves the keychain onto a shared surface loses the protection class that skill audits, so storage class and sharing scope are adjacent. - `hunting-mobile-secret-and-storage-exposure` - the broader secret-at-rest hunt, of which a shared-container or pasteboard leak is one exposure channel. - `auditing-android-component-exposure` - the Android analogue, where a content provider or exported component is the shared door another app reads through. - `auditing-mobile-webview-bridge-exposure` - a WebView that reads a shared surface can hand its contents to web content, chaining a shared-data leak into the bridge that skill audits. - [FINDING-SCHEMA.md](../../FINDING-SCHEMA.md) - source = the sensitive value placed on a shared surface, sink = the other app or process reading that surface, evidence = recovering the value outside the app's boundary on a test device.