Warmup Guide — iOS and Apple Platform App Security from First Principles
Zero-to-expert primer for the iOS module. It builds what an app security engineer reviews in an iOS app, from the ground up: the app sandbox and
Info.plist/entitlements, App Transport Security, the Data Protection classes and Keychain accessibility, URL schemes vs Universal Links, the data-lifecycle leaks (pasteboard/screenshots/backups/logs), privacy manifests and required-reason APIs, and why client-side checks (jailbreak detection, pinning) are not authorization. Builds on Phase 04 (mobile threat model) and Phase 05 (Apple OS internals). Authorized-lab-only, offline — analysis over app configuration metadata.
Table of Contents
- Chapter 1: The iOS App Threat Model
- Chapter 2: The Sandbox, Info.plist, and Entitlements
- Chapter 3: App Transport Security
- Chapter 4: Data Protection and the Keychain
- Chapter 5: URL Schemes, Universal Links, and IPC
- Chapter 6: The Data-Lifecycle Leaks
- Chapter 7: Privacy — Manifests, Required-Reason APIs, ATT
- Chapter 8: Why Jailbreak Detection and Pinning Are Not Authorization
- Lab Walkthrough Guidance
- Success Criteria
- Common Mistakes
- Interview Q&A
- References
Chapter 1: The iOS App Threat Model
Zero background. iOS is a hardened platform (Phase 05): mandatory code signing (only signed code runs), a per-app sandbox, a hardware Secure Enclave, and TCC privacy consent. That raises the floor — but it does not secure your app's design. The app-security questions are the same as Phase 04, asked in Apple's terms:
- What can the app reach? — its entitlements and
Info.plistdeclarations. - How does it talk to the network? — App Transport Security (Chapter 3).
- How is data protected at rest, and when is it readable? — Data Protection classes + Keychain accessibility (Chapter 4).
- Who can invoke it, with what input? — URL schemes / Universal Links (Chapter 5).
- Where does data leak around the secure store? — pasteboard, screenshots, backups, logs (Ch 6).
The threats you assess (the parties). The app developer (your review target), Apple (the platform), the backend the app calls, and the user — and an attacker who may physically hold the device (lost/stolen phone) or run a jailbroken device they control (Chapter 8). A finding names the responsible party.
Misconception to kill now. "iOS is secure, so the app is secure." iOS secures the platform; an app can still ship secrets in plaintext, disable TLS, store data with weak protection, expose a hijackable URL handler, or trust the client for authorization. The platform is the floor, not the app.
Chapter 2: The Sandbox, Info.plist, and Entitlements
The sandbox. Each app runs in its own container with a private filesystem; it cannot read another app's data (Phase 05). Sharing is explicit, via App Groups (a shared container) and Keychain access groups — both gated by entitlements. The sandbox gives you isolation for free; everything the app reaches beyond it is a review item.
Info.plist — the app's declaration. The property list bundled with the app declares its
configuration: supported URL schemes, the ATS policy (Chapter 3), required device capabilities,
usage-description strings (NSCameraUsageDescription, etc. — required to even request a TCC
permission), background modes, and more. It is the iOS analog of Android's manifest and your primary
review artifact.
Entitlements — capabilities baked into the signature. An entitlement is a signed key/value
granting a specific capability: Keychain access groups, App Groups, push, associated domains
(for Universal Links), HealthKit, network extensions, and powerful debug ones. Because entitlements
are part of the code signature, they can't be altered without breaking it. The review rule (Phase 05):
every entitlement must map to a justified feature — minimize them. Dangerous ones to flag:
get-task-allow (allows debugging — must be false in release), com.apple.security.cs.disable-library-validation
(loads unsigned libraries), wildcard or over-broad associated domains, and broad Keychain access
groups that share secrets too widely. A powerful entitlement is a finding only if unjustified or
abusable (not automatically) — the same nuance as Phase 04's exported-components.
Misconception to kill now. "macOS/iOS apps can't be tampered with because they're signed." Signing binds the bundle to a developer and fixes the entitlements — but it says nothing about whether those entitlements are appropriate, whether the app disables TLS, or whether it stores secrets safely. Review the configuration, not just the signature.
Chapter 3: App Transport Security
What ATS is. App Transport Security is the iOS policy (declared in Info.plist) that
forces network connections to use good TLS by default — HTTPS, TLS 1.2+, forward-secret ciphers,
and valid certificates. It exists because apps historically shipped cleartext or weak-TLS connections,
leaking data on hostile networks (Chapter 1's lost-phone / coffee-shop attacker).
The findings — ATS exceptions weaken it:
NSAllowsArbitraryLoads = true— the big one: disables ATS globally, permitting cleartext HTTP and weak TLS app-wide. A serious finding unless tightly justified and scoped.- Per-domain exceptions (
NSExceptionDomainswithNSExceptionAllowsInsecureHTTPLoads,NSExceptionMinimumTLSVersionlowered,NSExceptionRequiresForwardSecrecy = false) — narrower, but each is a hole; review the domain and the justification. NSAllowsLocalNetworking/NSAllowsArbitraryLoadsForMedia— scoped relaxations that still need review.
The right posture: ATS on, no global disable, exceptions only for specific justified domains, and
Apple now requires a justification for NSAllowsArbitraryLoads at App Store review — but
reviewers see apps ship it anyway.
Misconception to kill now. "We set NSAllowsArbitraryLoads to make development easier." That ships
a production app that accepts cleartext and weak TLS everywhere. ATS exceptions must be specific,
justified, and removed when not needed — like any security exception (Phase 03).
Chapter 4: Data Protection and the Keychain
Data Protection — file encryption tied to the lock state. iOS encrypts files with keys derived from the device key and the user passcode, and each file has a protection class controlling when its key is available:
NSFileProtectionComplete— decryptable only while the device is unlocked; the key is evicted shortly after lock. Strongest; use for the most sensitive data.NSFileProtectionCompleteUntilFirstUserAuthentication(the default) — available after the first unlock following boot, until shutdown. A pragmatic default (background apps work after first unlock).NSFileProtectionCompleteUnlessOpen— can be created/written while locked (for files written by background tasks).NSFileProtectionNone— encrypted only with the device key, available even when locked (i.e., readable by anyone who extracts the device storage with the device locked). Sensitive data atNoneis a finding.
The Keychain — the place for secrets. Credentials, tokens, and keys belong in the Keychain
(hardware-backed, per-item access control), not in UserDefaults, plist files, or app files. Each
item has an accessibility attribute mirroring the protection classes:
kSecAttrAccessibleWhenUnlocked— only while unlocked (strong)....AfterFirstUnlock— after first unlock (common for background access)....Always— deprecated and dangerous (readable while locked).- the
...ThisDeviceOnlyvariants — not synced to iCloud / restored to a new device (use for device-bound secrets). - plus access control flags binding an item to biometric/passcode (
SecAccessControlwith.userPresence/.biometryCurrentSet) and to the Secure Enclave (Phase 05).
Misconception to kill now. "We encrypted the token, so it's safe." If it's stored in
UserDefaults/a plist, or in the Keychain with Always accessibility, or in a file at
NSFileProtectionNone, it's exposed on a locked or backed-up device. Put secrets in the Keychain with
WhenUnlocked (or biometric-gated) accessibility, and pick Complete protection for sensitive files.
Chapter 5: URL Schemes, Universal Links, and IPC
Custom URL schemes — the hijackable entry point. An app can register a scheme
(myapp://pay?to=...) so other apps/web pages can launch it. The problem: any app can claim any
custom scheme — there is no ownership proof — so a malicious app can register myapp:// and
intercept links (or impersonate yours). And a URL handler is untrusted input from outside the
app (Phase 04's deep-link lesson): its parameters must be validated, and it must never perform a
sensitive action (a payment, a token exchange) without in-app confirmation and server-side
authorization.
Universal Links — the secure alternative. A Universal Link is a regular https:// URL that
opens your app if the app proves it owns the domain, via an apple-app-site-association (AASA)
file served over HTTPS on that domain and the associated-domains entitlement. Because ownership is
cryptographically/HTTPS-verified, another app cannot claim it — the iOS mirror of Android App Links.
Prefer Universal Links for anything sensitive; treat custom schemes as untrusted and unowned.
Other IPC surfaces. App Groups (shared container — validate what you read from it), pasteboard (Chapter 6), document providers, share extensions, and the keyboard. Each is a boundary where data crosses between apps.
Misconception to kill now. "Our custom URL scheme is private to our app." Custom schemes have no ownership enforcement — any app can register the same scheme and intercept or spoof it. Use Universal Links (verified domain ownership) and validate every parameter as untrusted.
Chapter 6: The Data-Lifecycle Leaks
Even with perfect Data Protection and Keychain use, data leaks around the secure store — the same lifecycle lesson as Phase 04 Chapter 9:
- Pasteboard. The general
UIPasteboardis system-wide and readable by other apps (and, pre-mitigation, synced across devices via Universal Clipboard). Copying a password/OTP/token to it leaks it. Use a named, non-persistent pasteboard for sensitive copies, setexpirationDate, and mark itemslocalOnly. - Screenshots / app switcher. iOS snapshots your UI for the app switcher; a sensitive screen is
captured to disk. Blur/obscure sensitive screens on
willResignActive. - Backups (iTunes/iCloud). App files and Keychain items may be backed up; secrets that shouldn't
leave the device need the
...ThisDeviceOnlyKeychain accessibility (not backed up/restored) and appropriate file-protection exclusion. - Logs / crash reports / analytics. Logging tokens, PII, or full requests sends secrets to logs, crash services, and third-party SDKs. Never log sensitive data (Phase 00 minimization).
- Third-party SDKs. Ad/analytics SDKs can exfiltrate pasteboard, IDFA, and PII — a supply-chain and privacy risk (Chapter 7, Phase 14).
Misconception to kill now. "The secret is in the Keychain, so we're done." If the same secret is copied to the system pasteboard, captured in an app-switcher snapshot, included in a crash log, or backed up to iCloud via a synced Keychain item, the Keychain protection is moot. Secure the whole lifecycle.
Chapter 7: Privacy — Manifests, Required-Reason APIs, ATT
Apple has turned privacy into enforced configuration that an app-security/privacy reviewer checks:
- Usage-description strings. To request a TCC-gated resource (camera, location, contacts,
photos, mic, tracking), the
Info.plistmust contain a purpose string (NS...UsageDescription). Missing string = the request crashes; vague/misleading string = a review and trust problem. - Privacy manifests (
PrivacyInfo.xcprivacy). A declaration of the data the app (and each bundled SDK) collects, the purposes, and the use of required-reason APIs — APIs (like accessing the file timestamp,UserDefaults, system boot time) historically abused for fingerprinting, which now require a declared approved reason. Undeclared use is rejected at App Store review. - App Tracking Transparency (ATT). Cross-app/cross-site tracking (using the IDFA) requires explicit user opt-in via the ATT prompt; tracking without it violates policy.
- Privacy "nutrition labels." The App Store data-collection disclosure must match what the app actually does.
For a reviewer: confirm the declared collection matches reality, that bundled SDKs' manifests are present and honest, and that required-reason APIs are justified — privacy is now a compliance-tested property (Phase 15), not a promise.
Misconception to kill now. "Privacy is legal's problem." On iOS, privacy is enforced configuration: missing usage strings crash, undeclared required-reason APIs and SDK manifests fail review, and tracking without ATT violates policy. It's an engineering review item.
Chapter 8: Why Jailbreak Detection and Pinning Are Not Authorization
The iOS echo of Phase 04 Chapter 10. Jailbreak detection and certificate pinning run on the device the attacker controls:
- Jailbreak detection raises analysis cost (a speed bump) but is bypassable on a jailbroken device with hooking frameworks (Frida, objection, Liberty) that stub out the checks. It must never be the control standing between an attacker and your data.
- Certificate pinning hardcodes the expected server cert/key so the app rejects a mis-issued or intercepted cert — good defense-in-depth against TLS interception, but it protects the network link, not authorization, and can be removed on a controlled device. It also needs a rotation plan (backup pins) or it bricks the app on key rotation (Phase 04).
The load-bearing point: the security decisions that matter are server-side. The server must authorize every request and never trust client-side attestation alone (Apple's App Attest / DeviceCheck provides server-verifiable device integrity signals — stronger than client-side jailbreak detection, but still an input to a server decision, not a boundary by itself).
Misconception to kill now. "We detect jailbreak and pin certs, so the API is protected." Both run on the client and are bypassable; the API is protected only by server-side authorization that doesn't trust the client — the same conclusion as web (P02) and Android (P04).
Lab Walkthrough Guidance
Two labs turn the iOS review surface into runnable analysis (synthetic config metadata):
- Lab 01 — ATS & Entitlements Analyzer. From
Info.plist/entitlements metadata, flagNSAllowsArbitraryLoadsand weak per-domain ATS exceptions, dangerous entitlements (get-task-allow, disable-library-validation, wildcard associated domains), and sensitive actions on custom URL schemes (Chapters 2–3, 5). - Lab 02 — Data-Protection & Privacy Evaluator. For each stored datum, check the Data Protection class / Keychain accessibility against its sensitivity, and flag pasteboard/backup/log leaks and undeclared required-reason APIs (Chapters 4, 6, 7).
LAB_MODULE=solution pytest -q # reference (passes)
pytest -q # your implementation after the TODOs
Success Criteria
You have internalized this module when you can, without notes:
- Review an
Info.plist/entitlements set and flag the dangerous entries with justification. - Explain ATS and why
NSAllowsArbitraryLoadsis a finding. - Choose the right Data Protection class and Keychain accessibility for a datum and justify it.
- Explain URL-scheme hijacking and why Universal Links are the secure alternative.
- Enumerate the data-lifecycle leaks (pasteboard, screenshots, backups, logs, SDKs) and the fixes.
- Explain privacy manifests, required-reason APIs, and ATT as enforced configuration.
- Explain why jailbreak detection and pinning are not authorization, and where App Attest fits.
Common Mistakes
- Shipping
NSAllowsArbitraryLoads(global ATS disable) from development into production. - Storing secrets in
UserDefaults/plist, or Keychain withAlwaysaccessibility, or files atNSFileProtectionNone. - Using custom URL schemes (no ownership) for sensitive actions instead of Universal Links.
- Copying secrets/OTPs to the system pasteboard; not obscuring sensitive screens in the app switcher.
- Backing up device-bound secrets (not using
ThisDeviceOnly); logging tokens/PII. - Undeclared required-reason APIs or dishonest SDK privacy manifests; tracking without ATT.
- Treating jailbreak detection / pinning as the authorization boundary.
Interview Q&A
Q: Where should an iOS app store an auth token, and why not UserDefaults?
A: In the Keychain, with kSecAttrAccessibleWhenUnlocked (or biometric-gated via SecAccessControl,
Secure-Enclave-backed for keys), and ThisDeviceOnly if it must not sync/restore. UserDefaults is an
unencrypted plist readable from a backup or a jailbroken device; the Keychain is hardware-backed with
per-item access control tied to the lock state.
Q: What is ATS and what would you flag?
A: App Transport Security forces HTTPS/TLS 1.2+/forward secrecy/valid certs by default. I'd flag a
global NSAllowsArbitraryLoads = true (cleartext/weak TLS app-wide) first, then per-domain exceptions
that allow insecure HTTP, lower the minimum TLS version, or disable forward secrecy — each needs a
specific justification or removal.
Q: Custom URL scheme vs Universal Link?
A: A custom scheme (myapp://) has no ownership enforcement — any app can register it and intercept
or spoof your links — so it's untrusted input and unsafe for sensitive actions. A Universal Link is an
https:// URL that opens your app only after domain ownership is proven via the apple-app-site-association
file plus the associated-domains entitlement, so it can't be hijacked. Prefer Universal Links and
validate every parameter regardless.
Q: Are jailbreak detection and pinning security controls? A: They're defense-in-depth, not boundaries — both run on a device the attacker controls and are bypassable (Frida/objection for jailbreak checks; pin removal on a controlled device). The real control is server-side authorization that never trusts the client; Apple's App Attest/DeviceCheck give a server-verifiable integrity signal, but it's an input to the server's decision, not a boundary itself.
References
- Apple: App Transport Security, Data Protection, Keychain Services,
SecAccessControl, Universal Links /apple-app-site-association, Privacy Manifests / required-reason APIs, App Tracking Transparency, App Attest / DeviceCheck; the Apple Platform Security Guide. - OWASP MASVS / MASTG (the iOS testing chapters); OWASP Mobile Top 10.
- Phase cross-references: P04 (mobile threat model, deep links, pinning), P05 (XNU, sandbox, TCC, Secure Enclave), P02 (TLS/identity), P14/P07 (SDK supply chain, privacy compliance).