9.1 — OWASP Mobile Top 10

Opening scenario

You’re four weeks from launching a fintech iOS app. The bank’s security team sends a 22-page audit. Half the findings reference “OWASP Mobile Top 10 M3” or “M4” with no further explanation. They want fixes before the security signoff meeting on Friday. You need the map between the abstract OWASP categories and the concrete iOS APIs that close each gap.

Context — what OWASP Mobile Top 10 is

OWASP (Open Web Application Security Project) publishes a periodic ranked list of the ten most impactful mobile security risks. The current generation (2024 refresh):

#CategoryiOS-flavored hit list
M1Improper Credential UsageHard-coded API keys, tokens in UserDefaults
M2Inadequate Supply Chain SecurityUnvetted SPM/CocoaPods deps, malicious typosquats
M3Insecure Authentication/AuthorizationAuth on client only, missing rate-limit, no Passkeys
M4Insufficient Input/Output ValidationNSPredicate format injection, web view XSS
M5Insecure CommunicationPlain HTTP, no TLS pinning, wildcard ATS exceptions
M6Inadequate Privacy ControlsMissing PrivacyInfo, over-broad permission strings
M7Insufficient Binary ProtectionsNo symbol strip, no jailbreak detection on high-value apps
M8Security MisconfigurationDebug logs in release, .plist with secrets, exposed URL schemes
M9Insecure Data StorageUserDefaults for tokens, unencrypted SQLite, Keychain with weak accessibility
M10Insufficient CryptographyCommonCrypto with ECB, hand-rolled key derivation, fixed IVs

For each category, there’s a specific Apple API or pattern that addresses it. Memorize the mapping — it’s the language security teams speak.

The mapping

M1 → Keychain + OAuth2/PKCE + ASWebAuthenticationSession
M2 → Package.resolved review, swift-package-manager checksums, dependabot, SBOM
M3 → ASAuthorizationController (Passkeys), LAContext (biometrics), server-side authz
M4 → Codable strict decoding, NSPredicate with %@ placeholders, WKWebView with strict config
M5 → URLSession + TLS 1.3 default + URLSessionDelegate pinning
M6 → PrivacyInfo.xcprivacy, App Tracking Transparency, minimum permissions
M7 → STRIP_SWIFT_SYMBOLS, IOSSecuritySuite, RASP libraries
M8 → xcconfig per env, no os_log without privacy specifier, Info.plist audit
M9 → Keychain (kSecAttrAccessibleWhenUnlocked), Data Protection class, SQLCipher
M10 → CryptoKit only (AES-GCM, ChaChaPoly, Curve25519)

Walking through a real audit

When a security report cites “M9 violation — login token persisted in UserDefaults”:

  1. Acknowledge specifically: “Confirmed: AuthManager.swift line 47 writes the JWT to UserDefaults.”
  2. Identify the right primitive: Keychain with kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly.
  3. Migrate safely: write to Keychain, fallback-read from UserDefaults for one release, then delete the UserDefaults entry on next launch.
  4. Add a test that fails if the token ever lands in UserDefaults again.

The senior signal isn’t fixing the bug — it’s the disciplined migration that doesn’t strand existing users.

In the wild

When the 2023 LastPass breach post-mortem traced back to a developer’s home-stored secrets, the entire mobile community re-audited. Apps that had M1 (credentials in source) discovered them in old PR history; M2 (supply chain) audits surfaced packages last updated in 2019 by single maintainers. The category names became standing agenda items in iOS security reviews.

Common misconceptions

  1. “OWASP Mobile Top 10 = OWASP Top 10.” Different project, different list. Web Top 10 (SQLi, XSS) overlaps with M4 but the mobile list emphasizes binary protections and storage that the web list ignores.
  2. “If we pass App Store Review, we’re secure.” Review checks ATS, permission strings, basic crash safety. It doesn’t audit Keychain accessibility flags or pinning configuration.
  3. “M7 (binary protections) doesn’t matter for normal apps.” True for low-value apps. False for banking, healthcare, IP-sensitive code. Know your threat model.
  4. “OWASP categories are rare edge cases.” M9 (insecure storage) and M5 (insecure comms) appear in roughly half of all iOS audits — these are the default failure modes.
  5. “Hand-rolled crypto is fine if we’re careful.” M10. Always use CryptoKit. Never write your own AES-GCM, never reuse an IV, never invent a KDF.

Seasoned engineer’s take

The Top 10 isn’t a list of paranoid worries — it’s a checklist that, if followed, eliminates 80 % of the bugs that lead to breach reports. Treat it as the iOS equivalent of the runtime errors a compiler catches: cheap to prevent, expensive to discover post-shipping. The pattern of senior security engineers is to internalize the M1–M10 mapping so completely that they can scan a PR diff and instantly think “M9 violation here” without consulting docs.

TIP: Pin a security-checklist.md to your repo’s root that lists each M-number with the project-specific control. Reviewers can tag PR comments [M9] or [M5] and link directly.

WARNING: Don’t dismiss findings as “theoretical.” The M-categories rank by impact-weighted frequency in real breaches, not by interestingness. M9 is #9 in the name but #2 in actual breach data.

Interview corner

Junior: “What’s the OWASP Mobile Top 10?” A ranked list of the ten most common security risks in mobile apps, refreshed periodically. For iOS each category maps to specific Apple APIs — e.g., M9 (insecure storage) maps to Keychain, M5 (insecure comms) maps to TLS pinning.

Mid: “How would you address an M9 finding in a legacy app storing tokens in UserDefaults?” Migrate the read/write to Keychain with kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly. Add a one-release transition that reads from Keychain first and falls back to UserDefaults so existing users don’t sign out; on first successful Keychain read, delete the UserDefaults copy. Add a test that asserts the token key never appears in UserDefaults.standard.dictionaryRepresentation().

Senior: “How do you operationalize OWASP Mobile Top 10 on a 12-engineer iOS team?” Three layers. First, a pinned security-checklist.md in the repo mapping each M-category to project-specific controls and review tags. Second, automated gates — SwiftLint security rules, semgrep for known bad patterns, dependabot for M2, and a CI check that fails if UserDefaults is written from AuthManager or any file matching *Auth*. Third, a quarterly threat-modeling exercise where we walk through the M-list against new features shipped that quarter and update controls. The point is making the abstract OWASP language concrete in the codebase so it shapes day-to-day PR review, not just annual audits.

Red-flag answer: “We rely on Apple’s sandboxing.” Sandbox blocks some classes of attack but does nothing for M9, M5, M3, M10. Sandbox alone is not a security strategy.

Lab preview

Lab 9.3 hands you an app with 8 deliberate OWASP violations across the M-categories. You’ll identify each one by category and fix it with the right primitive.


Next: 9.2 — Secure Data Storage