iOS App Security Checklist
Phase 0: Governance, environment, and CI/CD
Enforce CI gates
- Run static checks on every PR: swiftlint (or equivalent), unit/UI tests, dependency audit.
- Block release on High/Critical SAST/SCA/DAST findings; zero lint errors on release branches.
Secrets handling
- Ensure no secrets in source, Info.plist, storyboards, or logs.
- Use environment/secret manager for secrets.
- Redact secrets in analytics.
- Rotate keys/tokens periodically and on suspicion of leakage.
Evidence and traceability
- Archive scan reports with each artifact.
- Archive SBOM with each artifact.
- Archive build logs with each artifact.
- Archive release notes with each artifact.
Scanning automation
- Integrate a mobile SAST/DAST/SCA platform in CI/CD to run on each PR and pre‑release (e.g., Ostorlab).
- Automatically fail CI gates on High/Critical issues from SAST/DAST/SCA.
Phase 1: Threat modeling, data classification, and inventory
- Classify data (PII, credentials, tokens, payment) and map collection, processing, storage, and transmission.
- Identify trust boundaries (device, Keychain/File, URLSession, WebView, platform channels to native libs).
- Inventory third‑party SDKs; prefer well‑maintained, signed, least‑privilege SDKs; minimize count.
Phase 2: Build and configuration hardening (Xcode + Info.plist)
Xcode Release settings
- Strip symbols and dead code.
- Enable whole‑module optimization.
- Disable DEBUG flags in release builds.
- Exclude test/debug frameworks from the release.
- Remove development endpoints and feature flags from the release.
Code signing and entitlements
- Grant only necessary entitlements (no unused App Groups, Keychain Sharing, NFC, Bluetooth, etc.).
- Use automatic signing with dedicated release profiles.
- Protect signing credentials (e.g., CI secrets store, access controls).
App Transport Security (ATS)
- Set
NSAllowsArbitraryLoads = false. - Prefer TLS 1.2+ only.
- Use strict
NSExceptionDomainsonly when necessary and time‑boxed.
Info.plist hygiene
- Disable document sharing unless required:
-
UIFileSharingEnabled = false -
LSSupportsOpeningDocumentsInPlace = false - Minimize
LSApplicationQueriesSchemes; prefer Universal Links over custom schemes. - Provide accurate
NS[AppData/AppleEvents/SystemAdministration]UsageDescriptionstrings for all permissions.
Phase 3: Local storage and Keychain security
Keychain usage
- Store tokens/secrets in Keychain with the strongest feasible class:
-
kSecAttrAccessibleWhenUnlockedThisDeviceOnly - Or
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnlywhen applicable. - Gate sensitive items with
kSecAccessControlflags (e.g.,biometryCurrentSet,userPresence) when UX permits. - Delete Keychain items on logout.
- Consider device‑binding for high‑risk tokens.
File protection and databases
- Apply Data Protection to files:
NSFileProtectionComplete(default attributes or per‑file). - Encrypt sensitive databases/files (e.g., SQLCipher or equivalent).
- Never store secrets in plaintext.
Caches and derived data
- Avoid persisting PII in caches/temp.
- Purge sensitive caches/temp data on logout as needed.
- Purge sensitive caches/temp data in the background as needed.
- Do not write secrets to
UserDefaults.
Phase 4: Privacy safeguards (UI, clipboard, screenshots)
- Redact sensitive UI when backgrounded (blur or placeholder in
sceneWillResignActive/applicationWillResignActive). - Detect screen capture (
UIScreen.main.isCaptured) and adjust behavior for highly sensitive views. - Avoid reading the clipboard on app launch.
- Never place secrets on
UIPasteboard.general.
Phase 5: Network security and TLS/pinning
URLSession/ATS
- Enforce HTTPS to trusted hosts.
- Reject invalid certificates and hostnames.
- Disable HTTP fallbacks.
- Set strict timeouts.
- Implement retries with jitter where appropriate.
- Fail closed on TLS errors.
- Enforce use of TLS 1.2+ on server TLS settings.
Certificate pinning
- Prefer SPKI SHA‑256 pins.
- Include at least one backup pin per host.
- Implement pinning via
URLSessionDelegatetrust evaluation. - Validate behavior against MITM attempts.
- Validate behavior for expired/rotated leaf certificates.
- Plan safe pin rotation.
- Include telemetry on pin failures.
Cookies and tokens
- Use secure, HttpOnly, SameSite cookies for web flows.
- Avoid long‑lived bearer tokens on device.
- Clear cookies and web data after sensitive sessions.
Phase 6: Authentication, authorization, and session
Auth flows
- Use OAuth2/OIDC with PKCE for public clients.
- Never embed client secrets in the app.
- Prefer system browser (
ASWebAuthenticationSession/SafariViewController) over WebView for auth.
Tokens
- Use short‑lived access tokens.
- Store refresh tokens in Keychain.
- Rotate and invalidate tokens on logout.
- Rotate and invalidate tokens on device change.
- Bind sessions to device risk where appropriate.
- Detect anomalies (geo/IP/ASN changes) and respond.
Authorization
- Enforce authorization on the server; treat client checks as advisory.
- Validate for IDOR/BOLA vulnerabilities.
- Validate for privilege escalation issues.
Phase 7: WebView hardening (WKWebView)
- Use
WKWebViewonly when required. - Prefer app‑bound domains for isolation (
WKAppBoundDomains).
Defaults
- Disable JavaScript unless necessary.
- Disable
javaScriptCanOpenWindowsAutomatically. - Allowlist navigation via
WKNavigationDelegate. - Block
file://URLs. - Block
javascript:URLs. - Use non‑persistent data store for sensitive sessions.
- Clear
HTTPCookieStoreand website data on logout. - Ensure Web Inspector is disabled in release (iOS 16+
isInspectable = false).
Content security
- For first‑party web content, enforce CSP.
- Enforce HTTPS.
- Disallow mixed content.
Phase 8: Inter‑app communication and deep links
- Prefer Universal Links.
- Validate incoming link origins and parameters.
If custom URL schemes are used
- Choose a unique scheme.
- Validate all parameters.
- Defend against URL hijacking.
- Defend against open redirects.
- Limit
LSApplicationQueriesSchemesto known, necessary schemes.
Phase 9: Reverse engineering and tamper resilience
Reduce static leakage
- Strip symbols from binaries shipped to the store.
- Store dSYMs server‑side for crash symbolication.
- Remove verbose logs in release builds.
- Remove debug menus in release builds.
- Remove test endpoints in release builds.
- Remove feature toggles not intended for production.
Environment checks
- Log signals for jailbreak presence (files, syscalls, suspicious libs).
- Log signals for hooking frameworks.
- Log signals for debugger presence.
- Respond proportionally (degrade/block/telemetry) without relying solely on client checks.
Tamper testing
- Validate that repackaged builds fail integrity checks or server attestation.
- Validate that re‑signed builds fail integrity checks or server attestation.
- Treat client‑side checks as signals, never as the sole security control.
Phase 10: Cryptography and randomness
- Use platform crypto (
CryptoKit/CommonCrypto); do not implement custom cryptography. - Use AES‑GCM or ChaCha20‑Poly1305 for authenticated encryption.
- Use HKDF/PBKDF2 as KDFs with proper salt and adequate parameters.
- Generate keys/IVs with
SecRandomCopyBytes. - Never reuse IVs/nonces.
- Store cryptographic keys in Keychain.
Phase 11: Permissions, notifications, and identifiers
- Request minimum permissions required.
- Request permissions at point‑of‑use.
- Clearly explain value proposition to users when requesting permissions.
ATT (App Tracking Transparency)
- Request ATT only if necessary.
- Degrade gracefully if ATT is denied.
- Avoid fingerprinting and similar prohibited tracking techniques.
Identifiers
- Prefer
identifierForVendor. - Avoid IDFA unless ATT has been granted.
- Never use prohibited persistent identifiers.
Phase 12: Logging, analytics, and crash reporting
- Use
os_logwith privacy annotations. - Disable verbose logs in release builds.
- Redact PII from logs.
- Redact secrets from logs.
- Redact PII and secrets from analytics events.
- Redact PII and secrets from crash reports.
- Sample and aggregate analytics where possible.
- Ensure crash symbolication occurs server‑side.
- Never ship symbols with the app.
Phase 13: Testing, DAST, and runtime verification
Traffic interception tests
- Verify resistance to MITM with invalid certificate.
- Verify resistance to MITM with hostname mismatch.
- Verify resistance to MITM with untrusted CA.
- Confirm that pinning blocks interception where implemented.
Runtime inspection
- Confirm no secrets/PII in logs.
- Confirm Keychain items are present with correct ACLs.
- Confirm files have
NSFileProtectionComplete(or stricter where needed).
API abuse tests
- Test rate limiting.
- Test replay protections.
- Test pagination boundaries.
- Test for mass assignment vulnerabilities.
- Test for verbose error leakage.
Dynamic analysis
- Run mobile DAST while exercising core flows to surface transport misconfigurations.
- Use DAST to surface runtime issues (e.g., with Ostorlab).
- Export evidence for triage and re‑tests.
Phase 14: SBOM, and evidence
SBOM and dependencies
- Generate SBOM for Swift/Objective‑C code.
- Generate SBOM for embedded SDKs.
- Track CVEs affecting dependencies.
- Update dependencies regularly based on risk.
Evidence bundle
- Attach scan artifacts to the release.
- Attach SBOM to the release.
- Attach Info.plist diffs to the release.
- Attach entitlement lists to the release.
- Attach test reports to the release.
Phase 15: Reporting and standards alignment
Report
- Produce an executive summary.
- Document scope and methodology.
- Document detailed findings with PoCs and evidence.
- Assign risk ratings to findings.
- Provide remediation guidance.
- Include re‑test results.
OWASP MASVS mapping
- PLATFORM: Phases 2, 7–8, 11.
- STORAGE: Phases 3–4.
- CRYPTO: Phase 10.
- AUTH: Phase 6.
- NETWORK: Phase 5.
- CODE: Phases 2, 9, 12.
- RESILIENCE: Phase 9.
Practitioner quick‑reference
- Info.plist/ATS: No arbitrary loads; strict exception domains; disable document/file sharing unless needed.
- Keychain:
ThisDeviceOnlyclasses; optionalbiometryCurrentSet/userPresence; delete secrets on logout. - Files:
NSFileProtectionComplete; encrypt databases/files; avoidUserDefaultsfor secrets. - Network: HTTPS only;
URLSessionDelegatepinning (SPKI SHA‑256 with backups); verify MITM attempts fail. - Auth: OIDC + PKCE; short‑lived tokens; refresh tokens in Keychain; server‑side authorization; test IDOR/BOLA.
- WebView: Prefer system browser for auth; if
WKWebView, JS off by default, allowlist navigation, app‑bound domains, non‑persistent store for sensitive flows. - Privacy: Mask background snapshots; avoid clipboard secrets; minimize permissions and maintain accurate usage strings.
- Release hygiene: Strip symbols in app, keep dSYMs private; remove debug logs/menus; validate entitlements.
Example configurations and snippets
ATS (Info.plist)
- Configure
NSAppTransportSecurity: -
NSAllowsArbitraryLoads = false -
NSExceptionDomains = { yourdomain.com: { NSTemporaryExceptionAllowsInsecureHTTPLoads = false, NSIncludesSubdomains = true, NSTemporaryExceptionMinimumTLSVersion = TLSv1.2 } }
File protection (Swift)
- Use complete file protection:
-
try data.write(to: url, options: .completeFileProtection)
Keychain item (Swift gist)
- Configure Keychain item:
-
kSecClass: kSecClassGenericPassword -
kSecAttrAccessible: kSecAttrAccessibleWhenUnlockedThisDeviceOnly -
kSecAttrAccessControl: SecAccessControlCreateWithFlags(..., [.biometryCurrentSet, .userPresence])
URLSession pinning (outline)
- In
urlSession(_:didReceive:completionHandler:): - Evaluate
SecTrust. - Extract SPKI from the certificate.
- Compare SHA‑256 of SPKI to an allowlist of pins.
- Choose
.useCredentialor.cancelappropriately.
Lightweight workflows
Pre‑merge gate
- Run lints and tests.
- Run dependency audit.
- Trigger SAST/SCA scans.
- Block merge on High/Critical issues.
Pre‑release staging
- Validate Info.plist and entitlements.
- Build release binary.
- Confirm symbols are not shipped in the app.
- Run DAST while exercising core user flows (e.g., with Ostorlab) to validate TLS/pinning, storage protection, and logging hygiene.
- Fix issues and re‑test.
Post‑release monitoring
- Track crashes and performance.
- Rotate keys/tokens on a defined schedule.
- Monitor SDK advisories and CVEs.
- Keep SCA watching third‑party SDKs/libs (e.g., Ostorlab) to alert on new vulnerabilities.
- Trigger targeted re‑tests when new vulnerabilities are found.