Skip to content

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 NSExceptionDomains only 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]UsageDescription strings for all permissions.

Phase 3: Local storage and Keychain security

Keychain usage

  • Store tokens/secrets in Keychain with the strongest feasible class:
  • kSecAttrAccessibleWhenUnlockedThisDeviceOnly
  • Or kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly when applicable.
  • Gate sensitive items with kSecAccessControl flags (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 URLSessionDelegate trust 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 WKWebView only 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 HTTPCookieStore and 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.

  • 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 LSApplicationQueriesSchemes to 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_log with 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: ThisDeviceOnly classes; optional biometryCurrentSet/userPresence; delete secrets on logout.
  • Files: NSFileProtectionComplete; encrypt databases/files; avoid UserDefaults for secrets.
  • Network: HTTPS only; URLSessionDelegate pinning (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 .useCredential or .cancel appropriately.

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.