info@cetonix.com +91 (966) 512-1196 Mon–Fri, 09:30–18:00 IST
HomeInsightsiOS Keychain Accessibility Classes: The Line Between Locke

iOS Keychain Accessibility Classes: The Line Between Locked and Readable

The Keychain is hardware-backed and genuinely strong. The accessibility class you choose decides whether that strength applies to your data.

Security Testing Cetonix
iOS Keychain Accessibility Classes: The Line Between Locked and Readable

iOS gives applications unusually good defaults. The sandbox is tight, the Keychain is hardware-backed on every supported device, and data protection classes are applied to files automatically. An iOS assessment finds fewer storage findings than the equivalent Android assessment, and the ones it finds are subtler.

The most common of them is an accessibility class chosen without much thought.

What the classes mean

Every Keychain item carries an accessibility attribute controlling when it can be read:

  • kSecAttrAccessibleWhenUnlocked — readable only while the device is unlocked. The sensible default for anything tied to an active session.
  • kSecAttrAccessibleAfterFirstUnlock — readable after the first unlock following boot, and from then on even while locked. Necessary for background work; frequently used where it is not.
  • kSecAttrAccessibleAlways — readable regardless of lock state. Deprecated, still occasionally present in older code.
  • The ThisDeviceOnly variants of each — excluded from backups and not migrated to a new device.

The difference between the first two determines whether an attacker with your locked phone can read the item. That is not a subtle distinction, but the constant that expresses it is one word different, and there is no compiler warning for choosing the wrong one.

The pattern we find

A refresh token stored with AfterFirstUnlock because a background refresh task needed it once, and the class was never revisited. The access token is correctly scoped; the refresh token, which is longer-lived and more valuable, is readable while the device is locked.

The second common finding is missing ThisDeviceOnly. Without it, the item is included in encrypted backups and restored onto a new device. Whether that is acceptable depends on your threat model, but it should be a decision rather than a default.

Biometric binding is the control people think they have

A widespread implementation error is worth stating plainly.

The weak pattern: call LAContext.evaluatePolicy, receive a boolean, and if it is true, read the credential from the Keychain. The biometric check and the credential retrieval are separate operations, and the decision is made in application code. Under runtime instrumentation that boolean is trivially flipped.

The strong pattern: store the item with an access control created via SecAccessControlCreateWithFlags using .biometryCurrentSet or .userPresence. The Keychain will not release the item without a successful biometric evaluation. There is no boolean to flip, because the check is enforced by the platform rather than by your code.

.biometryCurrentSet additionally invalidates the item if the enrolled biometrics change — so adding a new fingerprint does not silently grant access to a credential enrolled under the old set.

The rest of the storage surface

Beyond the Keychain, an iOS assessment examines NSUserDefaults (a plist, not a secure store, and still used for tokens more often than it should be), Core Data and SQLite stores and their data protection classes, cached network responses, the pasteboard, and the snapshot the system takes when the app backgrounds — which captures whatever is on screen unless the app obscures it.

That last one produces a memorable finding roughly once a year: a banking or identity app whose app-switcher thumbnail shows full account details, because nothing was placed over the window on applicationWillResignActive.

Testing method

Real devices, both jailbroken and stock. Jailbroken for full runtime instrumentation and filesystem access; stock to confirm what a typical user’s environment actually exposes. A finding that only reproduces on a jailbroken device is a different severity from one that reproduces on a stock device with a backup extraction, and the report should distinguish them.

← SOC 2: What Auditors Actually Expect Against CC4.1 and CC7.1The ISO/IEC 27001:2013 Transition Deadline Is Close. Where That Leaves You →