| name | iOS-Pentesting-Skill |
| description | Comprehensive iOS app security audit with static analysis, dynamic instrumentation, source-to-sink tracing, IPC/component abuse analysis, and CVSS 4.0 reporting. Covers decompilation, Info.plist analysis, URL schemes and universal links, secrets detection, crypto analysis, Frida/Objection integration, and IPA modification. Use when user says "audit IPA", "analyze iOS app", "iOS pentest", "app security", "decompile IPA", "iOS vulnerability assessment", "reverse engineer iOS", "modify IPA", "URL scheme abuse", "bypass SSL pinning", "bypass jailbreak detection", "download IPA from App Store", or provides an IPA for security review, decompiled iOS sources, or decoded resources. Do NOT use for Android apps (use Android-specific skill), web application testing, or general programming help.
|
| license | Apache-2.0 |
| compatibility | macOS 11+ with Apple Silicon recommended (full functionality). Linux has ~90% compatibility with tool alternatives (see tool-installation-ios.md). Some features require jailbroken iOS device. Requires Frida, Objection, dsdump, and standard macOS toolchain (plutil, otool, codesign, security, lipo).
|
| allowed-tools | Bash(frida:*) Bash(objection:*) Bash(dsdump:*) Bash(class-dump:*) Bash(codesign:*) Bash(security:*) Bash(lipo:*) Bash(nm:*) Bash(strings:*) Bash(otool:*) Bash(jtool2:*) Bash(plutil:*) Bash(python3:*) Bash(ipa:*) Bash(unzip:*) Bash(zip:*) Bash(find:*) Bash(file:*) Bash(rg:*) Bash(xcrun:*) Bash(ideviceinstaller:*) Bash(idevicesyslog:*) Bash(ideviceinfo:*) Bash(idevicepair:*) Bash(ideviceimagemounter:*) Bash(afcclient:*) Bash(idevicecrashreport:*) Bash(ideviceprovision:*) Bash(swift-demangle:*) Bash(log:*) Bash(ipatool:*) Bash(plistutil:*) Bash(llvm-objdump:*) Bash(llvm-lipo:*) Bash(ldid:*) Read Write Edit Glob Grep |
| metadata | {"author":"DragonJAR SAS","version":"1.0.0","category":"mobile-security","tags":["ios","ipa-audit","static-analysis","dynamic-analysis","frida","objection","security-pentest","cvss-scoring","reverse-engineering","ipatool"]} |
iOS App Security Audit
Overview
Language Rule (CRITICAL): Match the user's language in your responses.
- If user speaks Spanish → reply in Spanish
- If user speaks English → reply in English
- If user speaks another language → reply in that language
- Default to English only when the user's language is unclear
This rule applies to ALL interactions: questions, explanations, findings, everything.
Deterministic 6-phase static analysis + optional dynamic confirmation workflow. Remove noise early, keep the bundle scope tight. Only report vulnerabilities where source, propagation, and sink are understood or clearly marked as needing dynamic confirmation.
When to Use
- User provides an IPA file for security review
- User asks to analyze decompiled iOS source code
- User needs to modify or repackage an IPA for testing
- User wants iOS mobile security testing or vulnerability assessment
- User needs help testing URL schemes, universal links, or IPC mechanisms
- User mentions iOS reverse engineering or app analysis
- User wants to acquire an IPA from the App Store (via ipatool — see references/ipa-extraction-guide.md §5)
New to iOS pentesting? Start with references/getting-started-ios.md for a 15-minute quick start guide.
Stuck on an issue? See references/troubleshooting-ios.md for centralized troubleshooting.
Quick workflow reference? See references/ios-pentesting-decision-tree.md for a visual decision tree of the complete testing workflow with environment options (jailbroken device, iOS Simulator, non-jailbreak).
Critical Rules
- NEVER report bare grep hits without traced context
- ALWAYS constrain searches to the app namespace (avoid framework noise)
- STOP and report immediately if decoding fails
- ALWAYS use imperative language in findings
- NEVER skip validation — if unsure, mark as "Needs Dynamic Confirmation"
- ALWAYS provide concrete PoC (frida script, objection command, or URL scheme payload)
- NEVER duplicate findings for the same root cause
Quality Note: Take your time to analyze thoroughly. Quality is more important than speed. Do not skip validation steps — a false positive is worse than a missed finding.
Reference: Before diving into specific analysis phases, consult references/ for detailed methodology on Mach-O analysis, crypto patterns, IPC abuse, and troubleshooting.
Interactive Decision Points
ALWAYS ask these questions BEFORE proceeding with the corresponding action.
Session Context (Remember for Entire Session)
The FIRST question establishes session context — remember the answer and reuse it.
When the user first provides an IPA or requests any action, establish:
- Target Environment — iOS Simulator OR Physical Device
- If Physical: Jailbreak status (jailbroken / non-jailbroken)
- If Simulator: iOS version/runtime
Store this context and reuse it for ALL subsequent actions in the session.
Rule: Only ask "Simulator or Physical Device?" ONCE per session. After the first answer, use that context for all install/hook/modify decisions without re-asking.
SimForge Requirement (Apple Silicon only): When Simulator is chosen, ALWAYS use SimForge to patch arm64 binaries for simulator compatibility. See references/simforge-ios-testing.md.
Example Flow:
- User: "Install this IPA"
- Agent: "Simulator or physical device?"
- User: "Simulator"
- Agent: [Uses SimForge to patch, then installs to simulator]
- ... later ...
- User: "Bypass SSL pinning"
- Agent: [Uses simulator commands directly, NO re-ask]
When Installing an IPA
User request: "Install this IPA", "Install the app", "Deploy the IPA"
Required questions:
- Target environment? — iOS Simulator OR Physical Device (jailbroken/non-jailbroken)
- If Physical Device: Is it jailbroken? (determines if Frida server is available)
- If Simulator: Which iOS version/runtime? (xcrun simctl list)
Commands based on answer:
- Simulator: Use SimForge to patch arm64 binary →
xcrun simctl install <UDID> <app-path>
See references/simforge-ios-testing.md for complete SimForge workflow
- Physical (jailbroken):
ideviceinstaller install <ipa>
- Physical (non-jailbroken): Needs re-signing with provisioning profile first
When Dynamic Analysis is Requested
User request: "Hook this app", "Bypass SSL pinning", "Intercept traffic", "Runtime analysis"
Required questions:
Target environment? — Use session context (established above)
- Is Frida server running? — Verify with
frida-ps -U (device) or frida-ps -D (simulator)
- App bundle ID or process name? — Need exact identifier for attachment
When Modifying/Repackaging an IPA
User request: "Modify this IPA", "Patch the app", "Re-sign", "Repackage"
Required questions:
- What modification? — Bypass protection, patch code, change resources, etc.
Target device type? — Use session context (jailbroken vs stock)
- Provisioning profile available? — Required if stock device
When URL Scheme Testing
User request: "Test URL schemes", "Test deep links", "IPC testing"
Required questions:
- Test target? — Static analysis (plist grep) OR Runtime (use session context)
- Specific schemes to test? — Or test all found in Info.plist
- Payload injection needed? — Yes for XSS/parameter testing, No for enumeration only
When Crypto/Keychain Testing
User request: "Test encryption", "Keychain analysis", "Crypto review"
Required questions:
- Analysis type? — Static (code patterns) OR Runtime (Frida hooks)
- Target algorithms? — CommonCrypto, CryptoKit, third-party, or all
- Key extraction needed? — Yes (requires Frida) or No (pattern analysis only)
Rule: NEVER assume the target environment. ALWAYS ask before executing install/hook/modify commands.
Execution Model
Tools to use: bash, write, edit, read, glob, grep for core workflow.
Toolchain Requirements
Before starting, verify these tools are installed:
- Frida (
frida --version) — pinned version in references/tool-versions.md; ⚠️ frida-server on device must match the host frida core version (frida --version) exactly
- Objection 1.12.4 (
objection --version) — Note: Objection is in maintenance mode
- dsdump dsdump_b2 (project archived Dec 2025) — Swift class dump for modern iOS binaries
- class-dump (optional) — Objective-C class dump for legacy apps
- plutil (system) — plist manipulation (preinstalled on macOS)
- codesign (system) — code signing (preinstalled on macOS)
- security (system) — keychain access (preinstalled on macOS)
- lipo (system) — fat binary manipulation (preinstalled on macOS)
- nm (system) — symbol extraction (preinstalled on macOS)
- strings (system) — string extraction (preinstalled on macOS)
- otool (system) — Mach-O analysis (preinstalled on macOS)
- jtool2 (optional) — Advanced Mach-O analysis
- SimForge (REQUIRED for arm64 apps on Simulator, Apple Silicon only) —
simforge — Patches Mach-O LC_BUILD_VERSION to run arm64 iOS apps in the simulator with dylib injection (no jailbroken device required). See references/simforge-ios-testing.md.
- ipatool (optional) —
ipatool --version — Download IPAs from the App Store. Output is FairPlay-encrypted. See references/ipa-extraction-guide.md §5.
- Python 3.10+ (
python3 --version)
Run scripts/preflight-check.sh (bash), scripts/preflight_check.py (universal, JSON output), or scripts/preflight-check.ps1 (PowerShell) to verify all tools. See references/environment-setup-ios.md for installation instructions. See references/tool-versions.md for version requirements.
Phase 0 — Extract and Detect Framework
Extract IPA
unzip app.ipa -d extracted/
cd extracted/Payload/YourApp.app/
Mach-O Analysis
otool -l YourApp | rg -A 10 "LC_ENCRYPTION_INFO(_64)?"
lipo -info YourApp
file YourApp
dsdump YourApp > classdump-swift.txt
class-dump YourApp > classdump-objc.txt
Reference: references/macho-binary-analysis.md for the complete Mach-O analysis methodology (LC_ENCRYPTION_INFO, LC_CODE_SIGNATURE, segment layout, symbol tables, strip/binary thinning).
Reference: references/advanced-tools-ios.md for the deep-dive tool set (Corellium, Hopper, Ghidra, frida-trace, lldb).
Reference: references/bitcode-analysis.md when the binary is bitcode-enabled (older App Store builds).
Reference: references/tool-installation-ios.md for tool install and troubleshooting.
Reference: references/libimobiledevice-guide.md for device pairing, syslog, backup, and filesystem access via the libimobiledevice toolchain.
Encrypted binary recovery: if cryptid == 1 after otool -l, use the bundled assets/frida-scripts/dump-ios.js to dump the decrypted binary from memory.
Framework Detection
Identify the app's architecture early to tailor analysis.
| Framework | Detection Method | Key Artifacts |
|---|
| React Native | rg "RCTBridgeModule" · Check for libReactNative.a | index.ios.bundle, libReactNative.a |
| Flutter | Check Frameworks/ for Flutter.framework and App.framework · Check for FLT* keys in Info.plist (FLTEnableImpeller, FLTEnableSurfaceControl) | App.framework, Flutter.framework, flutter_assets/ |
| Cordova/Ionic | rg "cordova" in Info.plist · Check www/ directory | cordova.js, config.xml |
| Xamarin | rg "xamarin" · Check for Mono runtime | libmonosgen-2.0.dylib |
| Unity | rg "UnityEngine" · Check for UnityFramework.framework | Data/Managed/, UnityFramework.framework |
| Swift Native | Check for Swift symbols · dsdump output shows Swift classes | Swift-only codebase |
| Objective-C | Check for ObjC runtime · class-dump shows ObjC classes | ObjC-only codebase |
Reference: references/framework-detection-ios.md for complete detection scripts, Frida detection hooks, and framework-specific security considerations.
Framework-specific deep dives (load the relevant one when you detect the framework):
references/react-native-ios-security.md
references/flutter-ios-security.md
references/cordova-ios-security.md
references/xamarin-ios-security.md
references/unity-ios-security.md (also covers running Unity IL2CPP games in the simulator — Metal heap fix — and IL2CPP reverse engineering with Il2CppDumper on macOS)
references/swiftui-security-deep-dive.md (even for native SwiftUI apps)
references/core-ml-security.md and references/core-ml-security-expanded.md (apps with on-device ML)
Obfuscation Detection
- Swift Obfuscation: Generic class names (
a.b.c, x_1, internal_), mangled symbols
- LLVM Obfuscator: Mixed naming, string encryption
- Custom Obfuscation: Unusual patterns, mixed naming schemes
- Third-Party Packers: iMAS, Arxan, GuardSquare (iXGuard), DexGuard iOS
Reference: references/static-analysis-patterns-ios.md for detailed detection patterns.
Reference: references/obfuscation-detection-ios.md for SwiftShield, IOSSecuritySuite, Arxan, and Irdeto detection methodology.
OPTIONAL: MobSF Integration
Reference: references/mobsf-integration-guide.md for complete MobSF setup and API usage.
The iOS-Pentesting-Skill offers optional Mobile Security Framework (MobSF) integration for automated static and dynamic analysis.
Key Points:
- ✅ OPTIONAL: User choice, no hard dependency
- ✅ NON-BLOCKING: Works perfectly without MobSF
- ✅ ENHANCEMENT: MobSF results complement manual analysis
- ✅ CORRELATION: Findings merged with manual analysis
Interactive Setup (automatically prompts):
python3 scripts/setup_mobsf.py
This script will:
- Check if MobSF is already installed
- Offer installation options if not found
- Configure API access
- Test connectivity
- Save configuration for future sessions
Quick Start (Docker):
./scripts/install-mobsf-docker.sh
python3 scripts/mobsf_config.py set-url http://127.0.0.1:8000
python3 scripts/mobsf_config.py set-key generate
python3 scripts/mobsf_config.py status
Using MobSF in Analysis:
python3 scripts/mobsf_upload.py --ipa app.ipa
python3 scripts/mobsf_export.py --scan-id <SCAN_ID>
python3 scripts/mobsf_export.py --scan-id <SCAN_ID> --format json
Alternative: Local Install (no Docker):
python3 scripts/mobsf_detect.py
./scripts/install-mobsf-local.sh
./scripts/run-mobsf-local.sh
Correlation: merge MobSF's automated detections with your manual source-to-sink findings to deduplicate and enrich evidence using scripts/mobsf_findings_correlator.py.
NOTE: MobSF integration is OPTIONAL. The skill works perfectly without it.
Phase 1 — Attack Surface Mapping
Analyze Info.plist
plutil -p Info.plist
plutil -extract CFBundleURLTypes xml1 -o - Info.plist
plutil -extract NSAppTransportSecurity xml1 -o - Info.plist
/usr/libexec/PlistBuddy -c "Print :CFBundleURLTypes:0:CFBundleURLSchemes" Info.plist
URL Schemes (Deep Links)
Extract and document all custom URL schemes:
| Key | What It Controls | Security Impact |
|---|
| CFBundleURLSchemes | Custom schemes (e.g., myapp://) | URL scheme injection via malicious URLs |
| CFBundleURLTypes | Scheme declarations | Attack surface enumeration |
| NSAppTransportSecurity | TLS/ATS settings | Cleartext traffic, insecure connections |
Info.plist Security Keys
| Key | What It Controls | Security Checks |
|---|
| UIBackgroundModes | Background capabilities | Unintended background data collection |
| NSPhotoLibraryUsageDescription | Photo access | Permission request clarity, photo library scope |
| NSCameraUsageDescription | Camera access | Permission request clarity |
| NSMicrophoneUsageDescription | Microphone access | Permission request clarity |
| NSLocationWhenInUseUsageDescription | Location access | Permission request clarity |
| NSLocationAlwaysAndWhenInUseUsageDescription | Background location | Justification for always-on tracking |
| NSFaceIDUsageDescription | Face ID biometric | Required since iOS 11; fallback policy |
| NSContactsUsageDescription | Contacts access | PII extraction scope |
| NSHealthShareUsageDescription | HealthKit read | PII / health data scope |
| NSHealthUpdateUsageDescription | HealthKit write | Health data write justification |
| NSRemindersUsageDescription | Reminders access | PII scope |
| NSBluetoothPeripheralUsageDescription | Bluetooth (legacy) | Legacy key, replaced in iOS 13 |
| NSBluetoothAlwaysUsageDescription | Bluetooth (modern) | iOS 13+ required for always-on BLE |
| NSSpeechRecognitionUsageDescription | Speech recognition | Audio data exfiltration scope |
| NSUserTrackingUsageDescription | App Tracking Transparency | Required for IDFA access since iOS 14.5 |
| NSAppTransportSecurity | ATS exceptions | See references/ats-configuration-guide.md |
| LSApplicationQueriesSchemes | canOpenURL whitelist | Enumerates installed apps; surface for fingerprinting |
| ITSAppUsesNonExemptEncryption | Export compliance | Triggers App Store export compliance prompt |
| UIFileSharingEnabled | iTunes file sharing | Data exposure via iTunes / Files app |
| UISupportedExternalAccessoryProtocols | External accessories | Attack surface expansion |
| UIRequiresPersistentWiFi | WiFi requirement | Network behavior predictability |
| NSAppClipboardUsageDescription | Pasteboard read (UIPasteboard) | macOS Catalyst only; iOS doesn't require usage description — audit clipboard usage via static analysis |
Entitlements Analysis
codesign -d --entitlements - YourApp.app/YourApp
| Entitlement | Purpose | Security Impact |
|---|
| keychain-access-groups | Shared keychain access | Cross-app data sharing |
| get-task-allow | Debugger attachment | Debug mode in production — must be false in release |
| application-groups | App group containers | Shared data between apps / extensions |
| com.apple.developer.applesignin | "Sign in with Apple" capability | Required when offering third-party SSO |
| com.apple.developer.in-app-payments | Apple Pay capability | Payment flow integrity |
| com.apple.developer.icloud-container-identifiers | iCloud document storage | Data exfiltration via iCloud sync |
| com.apple.developer.icloud-services | iCloud (CloudKit, Key-Value) | CloudKit data scope |
| com.apple.developer.ubiquity-container-identifiers | iCloud ubiquity (Documents) | Document sync scope |
| com.apple.developer.associated-domains | Universal Links / Handoff | Deep link / Universal Link routing |
| com.apple.developer.default-data-protection | Default NSFileProtection class | Determines at-rest encryption for new files |
| com.apple.developer.pass-type-identifiers | Wallet pass type | Pass authentication scope |
| com.apple.developer.healthkit | HealthKit access | Health data scope |
| com.apple.developer.homekit | HomeKit access | Smart home device control scope |
| aps-environment (production / development) | Push notifications | APNs token handling, dev vs prod routing |
| com.apple.developer.networking.wifi-info | WiFi network info (iOS 13+) | SSID/BSSID exposure; opt-in |
| com.apple.security.application-groups | App group containers (App Sandbox — macOS only) | N/A on iOS; do not expect in IPA entitlements |
| com.apple.security.network.client | Outbound network (App Sandbox — macOS only) | N/A on iOS; the iOS sandbox always allows outbound |
| com.apple.security.network.server | Inbound network (App Sandbox — macOS only) | N/A on iOS; iOS apps cannot bind listening TCP/UDP sockets on cellular or WiFi (sandbox restriction) |
App Extensions Detection
find . -name "*.appex" -type d
Common extensions:
- Today Widget:
TodayExtension.appex
- Share Extension:
ShareExtension.appex
- Action Extension:
ActionExtension.appex
- Notification Content:
NotificationContentExtension.appex
Reference: references/info-plist-checklist.md — complete Info.plist key checklist (47 keys).
IPC / URL scheme abuse: see references/url-scheme-security-guide.md and references/universal-links-guide.md.
App extensions (Today / Share / WidgetKit / Notification Content / Keyboard): references/app-extensions-security.md.
Privacy manifest (PrivacyInfo.xcprivacy, App Tracking Transparency): references/privacy-manifest-ios.md and references/ios-privacy-testing.md.
iOS version diffs (iOS 15 → 18 changes that affect attacks): references/ios-version-security-changes.md.
Enterprise & MDM Apps
In-house / VPP / DEP apps and MDM-managed devices expand the attack surface via configuration profiles, managed app config, and enterprise distribution certificates.
- Configuration profiles (
.mobileconfig): inspect for over-broad payloads, injected trusted CAs, and VPN/proxy settings.
- Managed app config: read the
NSUserDefaults key com.apple.configuration.managed.
- Enterprise certs: validate the signing identity and provisioning scope (
codesign -dvv).
Reference: references/enterprise-app-testing.md, references/mdm-security-testing.md, and references/configuration-profile-abuse.md.
Dynamic (Phase 4): assets/frida-scripts/mdm-bypass.js (MDM restriction bypass) and assets/frida-scripts/enterprise-cert-bypass.js (enterprise cert trust bypass).
Automation: references/automation-scripts-ios.md and scripts/auto-audit-static-ios.sh (one-shot static analysis driver for Phases 0–3).
Data Storage Locations (Quick Reference)
When analyzing data storage, check these locations for sensitive data exposure:
| Location | Path Pattern | What to Check | Tool |
|---|
| NSUserDefaults | Library/Preferences/*.plist | Tokens, user data, feature flags, config | plutil -p |
| Core Data | Library/Application Support/*.sqlite | Cached API responses, user records, local DB | sqlite3 |
| Keychain | System keychain database | Credentials, encryption keys, certificates | keychain-dumper, Frida |
| Cookies | Library/Cookies/*.binarycookies | Session cookies, authentication tokens | Binary parsing |
| Cache | Library/Caches/ | Cached API responses, images with PII | find, strings |
| Snapshots | Library/SplashBoard/Snapshots/ | App state screenshots (may contain PII) | Image review |
| Keyboard | Library/Keyboard/ | Autocomplete entries with sensitive input | strings |
| Pasteboard | System pasteboard | Copied passwords, tokens, sensitive data | Frida hook |
| WebView Storage | Library/WebKit/WebsiteData/ | LocalStorage, IndexedDB, cookies | sqlite3 |
| Tmp | tmp/ | Temporary files, may contain sensitive data | find, strings |
Full reference: references/data-protection-api-guide.md
Testing: Use assets/frida-scripts/pasteboard-monitor.js, assets/frida-scripts/keylogger-basic.js
Phase 2 — Targeted Triage
Scoped Grep Patterns
ALWAYS grep within the app namespace only. Use patterns from references/static-analysis-patterns-ios.md:
| Category | Example Patterns (ObjC/Swift) | What to Look For |
|---|
| WebView sinks | loadRequest, loadHTMLString, evaluateJavaScript | Loading untrusted URLs |
| IPC sources | openURL(_:), application(_:open:), continue(_:) | Unsanitized data entry from URL schemes |
| Keychain | SecItemAdd, SecItemCopyMatching, kSecAttrAccessible | Insecure storage, weak accessibility |
| UserDefaults | UserDefaults, standardUserDefaults, set | Cleartext storage of sensitive data |
| Pasteboard | UIPasteboard.general, string, setItems | Data exposure via clipboard |
| Hardcoded secrets | password.*=, api[_-]?key, "sk_live_, secret | Credentials in code |
| Crypto | kCCAlgorithmAES, kCCOptionECBMode, MD5, SHA1 | Weak algorithms, insecure modes |
| TLS/ATS | NSAllowsArbitraryLoads, NSExceptionDomains | Disabled certificate validation |
| Logging | NSLog, print, os_log | Sensitive data in logs |
| File I/O | writeToFile, FileManager, createFile | Path traversal, insecure file ops |
| Background | beginBackgroundTask, BGTaskScheduler | Unintended background data collection |
| Biometric | LocalAuthentication, evaluatePolicy | Biometric bypass, fallback to PIN |
| SQLite | sqlite3_exec, sqlite3_prepare_v2 | SQL injection |
| CoreData | NSPersistentContainer, execute | Data query injection |
Binary Analysis Commands
strings YourApp | rg -i "(password|key|secret|token|api)"
nm -gU YourApp | rg " T "
otool -L YourApp
class-dump YourApp
dsdump YourApp
nm -gU YourApp | rg -i "(AES|DES|MD5|SHA)"
Resource File Analysis
Check Info.plist and embedded plists for secrets:
rg -i "(key|token|secret|password|api)" Info.plist
rg -i "(key|token|secret|password|api)" -g "*.plist"
Reference: references/static-analysis-patterns-ios.md for grep patterns organized by vulnerability type.
Reference: references/objc-security-patterns.md and references/swift-security-patterns.md for language-specific pitfalls (swizzling, KVO, type-safety, generics).
Reference: references/runtime-hardening-checks-ios.md for the runtime hardening controls that are routinely missed: background snapshot obfuscation, custom keyboard risk, AutoFill, screen recording detection, URLSession audit, WKWebView cache cleanup, file protection classes, biometric replay protection, nscurl ATS testing, Universal Links validation, and app group containers.
Phase 2 — Per-area reference files
Use these when a category from the table above lights up:
- Crypto / CommonCrypto →
references/commoncrypto-analysis.md
- CryptoKit (Swift crypto) →
references/cryptokit-hook-ios.js
- Keychain →
references/keychain-security-guide.md
- UserDefaults →
references/userdefaults-security.md
- CoreData →
references/coredata-security.md
- UIPasteboard →
references/pasteboard-security.md
- File protection / NSFileProtection* →
references/data-protection-api-guide.md
- Deserialization security →
references/insecure-deserialization-ios.md
- Passkeys / WebAuthn →
references/passkeys-security-ios.md
- Swift Concurrency →
references/swift-concurrency-security.md
- CloudKit / iCloud sync →
references/cloudkit-security-ios.md
Phase 2 — Runtime Frida scripts
Map the script to the finding category:
- Cryptography →
crypto-hook-ios.js
- CryptoKit (Swift crypto) →
cryptokit-hook-ios.js
- Keychain / Secure Enclave →
keychain-dumper.js, secure-enclave-probe.js
- UserDefaults →
nsuserdefaults-dumper.js
- CoreData →
coredata-interceptor.js
- Pasteboard →
pasteboard-monitor.js, clipboard-exfiltration.js
- File protection →
data-protection-check.js, file-protection-enumerator.js
- ATS / cleartext →
app-transport-security.js
- Network →
network-interceptor-ios.js
- Network.framework (iOS 13+) →
nwconnection-hook-ios.js
- Deserialization →
deserialization-hook-ios.js
- Passkeys/WebAuthn (iOS 16+) →
passkeys-hook-ios.js
- Swift Concurrency →
swift-concurrency-monitor-ios.js
SBOM & Supply Chain (OWASP M2)
Enumerate embedded frameworks, third-party SDKs, and their known CVEs:
python3 scripts/sbom_generator.py --input app.ipa --format all --output sbom/
python3 scripts/dependency_scanner.py --sbom sbom/sbom.json --check-cves --check-licenses --output dep-scan.json
Reference: references/sbom-supply-chain-guide.md for SBOM formats (CycloneDX/SPDX) and supply-chain risk methodology; references/third-party-sdk-analysis.md for per-SDK review (trackers, network behavior, ATS exemptions).
Runtime SDK behavior: assets/frida-scripts/sdk-tracer.js enumerates loaded third-party SDKs and hooks their methods for actual network/credential behavior (often more accurate than the static SDK inventory).
MobSF correlation (optional): scripts/mobsf_findings_correlator.py merges your manual findings with MobSF's automated ones, deduplicating overlapping detections.
Phase 3 — Data Flow Tracing
Source-to-Sink Methodology
Map data flow from untrusted sources to dangerous sinks:
Common Sources (iOS)
| Source | Method | Example |
|---|
| URL Schemes | application(_:open:) | Malicious scheme URLs |
| Universal Links | application(_:continueUserActivity:) | Universal link abuse |
| Pasteboard | UIPasteboard.general.string | Data from clipboard |
| App Groups | Shared container NSFileManager | Inter-app data |
| XPC | NSXPCConnection | Inter-process communication |
| Keychain | SecItemCopyMatching | Stored credentials |
| Notifications | UNUserNotificationCenter | Notification payloads |
| WebView JS Bridge | WKScriptMessageHandler | Untrusted JS calls |
Common Sinks (iOS)
iOS scope: iOS apps run in a sandbox and cannot spawn child processes (no NSTask, no Process, no popen). Realistic "execution" paths on iOS go through WebView JS bridges, XPC, URL schemes, or app group data exfiltration — not OS command execution.
| Sink | Method | Impact |
|---|
| WebView Load | WKWebView.load(_:), loadHTMLString(_:baseURL:), evaluateJavaScript(_:completionHandler:) | XSS, Phishing, JS bridge abuse |
| WebView JS Bridge | WKScriptMessageHandler callbacks, WKScriptMessageHandlerWithReply, window.webkit.messageHandlers.* | Native code execution via injected JS |
| File Operations | Data.write(to:), String.write(toFile:atomically:encoding:), FileManager.createFile(atPath:contents:attributes:) | Path traversal, sandbox escape, LFI |
| XPC (ObjC) | NSXPCConnection.remoteObjectProxy method invocations, NSXPCListenerEndpoint | IPC injection, privilege escalation |
| XPC (C-level) | xpc_connection_send_message, xpc_connection_send_barrier | XPC message injection, low-level IPC abuse |
| openURL | UIApplication.open(_:options:completionHandler:) | URL scheme/Universal Link injection, app-to-app attack |
| canOpenURL | UIApplication.canOpenURL(_:) (requires LSApplicationQueriesSchemes) | Installed app enumeration |
| Keychain Write | SecItemAdd, SecItemUpdate, SecItemDelete | Credential poisoning, keychain clearing |
| Pasteboard Write | UIPasteboard.general.setItems(_:options:) | Clipboard exfiltration, data leakage to other apps |
| SQLite | sqlite3_exec, sqlite3_prepare_v2 + binding, FMDB.executeQuery | SQL injection |
| CoreData | NSFetchRequest with attacker-influenced NSPredicate | Predicate injection, data exfiltration |
| UserDefaults Write (Swift) | UserDefaults.standard.set(_:forKey:), UserDefaults.standard.set(_:forKey:) variants | Config tampering, sensitive data persistence |
| UserDefaults Write (ObjC) | [[NSUserDefaults standardUserDefaults] setObject:forKey:], setBool:forKey:, setInteger:forKey: | Config tampering, sensitive data persistence |
| Logging | NSLog, os_log, print | Sensitive data in logs, log injection |
| Notifications | UNUserNotificationCenter.add(_:withCompletionHandler:), UNMutableNotificationContent | Notification payload abuse, action hijacking |
| Biometric | LAContext.evaluatePolicy(_:localizedReason:reply:) | Biometric bypass, fallback to device passcode |
Decision Rules
| Rule | Condition | Action |
|---|
| 1 | Direct flow source → sink | Report as Likely |
| 2 | Indirect flow via static analysis | Report as Likely if path clear |
| 3 | Dynamic/reflective call | Mark as Needs Dynamic Confirmation |
| 4 | Native boundary | Mark as Needs Dynamic Confirmation |
| 5 | Library code | Verify if app wraps securely |
| 6 | No sanitization | Escalate severity |
Manual Checks Grep Misses
| Check | Why grep misses | How to verify |
|---|
| Runtime permissions | requestAuthorization() calls | Trace completion handlers |
| Custom entitlement protections | Entitlement checks in code | Look for permission checks |
| URL scheme handling | openURL(_:) hides parameter extraction | Follow URL parsing and validation |
| Shared containers | App groups + shared paths | Map containerURL(forSecurityApplicationGroupIdentifier:) |
| XPC communication | Interface definitions + dynamic calls | Trace XPC connection setup |
| WebView JS Bridge | WKScriptMessageHandler + JS code | Map message handlers to JS injection points |
Reference: references/deep-link-exploitation-ios.md for modern attack vectors: URL scheme injection, universal link abuse, WebView XSS, pasteboard attacks, XPC injection, app group data leakage, notification abuse.
Reference: references/url-scheme-security-guide.md for a complete scheme-by-scheme audit checklist (registration, parsing, validation, origin checks).
Reference: references/ipc-xpc-guide.md and references/xpc-services-security.md for the XPC connection lifecycle and audit patterns.
Reference: references/webview-security-ios.md for WKWebView and UIWebView attack surface (uiwebview-interceptor.js runtime hook).
Reference: references/notification-security.md for APNS token handling and notification payload abuse.
Reference: references/app-groups-security.md for shared container attack surface and app-groups-inspector.js runtime hook.
Phase 3 — Runtime Frida scripts
- URL scheme / openURL →
url-scheme-monitor.js, deeplink-security-analyzer.js, deep-link-fuzzer.js
- XPC →
xpc-tracer.js
- WebView →
uiwebview-interceptor.js
- Push notifications →
notification-interceptor.js
- App groups →
app-groups-inspector.js
- BGTask / background URLSession →
background-fetch-monitor.js
- Clipboard as exfiltration channel →
keylogger-basic.js (only when relevant)
Phase 4 — Dynamic Analysis (Optional)
Use when static analysis hits a wall: obfuscation, reflection, native code, runtime protections.
Simulator-Based Testing (Apple Silicon, no jailbreak required)
When no jailbroken device is available, SimForge lets you run a decrypted arm64 iOS app in the iOS simulator and inject dylibs (e.g., Frida Gadget) without frida-server. Use it as a fast first iteration before escalating to a physical device.
simforge convert /path/to/Payload/YourApp.app
codesign -f -s - /path/to/Payload/YourApp.app/Frameworks/*
codesign -f -s - /path/to/Payload/YourApp.app
xcrun simctl boot "iPhone 15"
xcrun simctl install booted /path/to/Payload/YourApp.app
simforge launch --bundleid com.example.app --dylib /path/to/frida-gadget.dylib
frida -H 127.0.0.1:27042 -n Gadget -l assets/frida-scripts/ssl-pinning-bypass-ios.js
Prerequisite for HTTP(S) interception in the simulator: install your proxy's CA cert into the simulator's trust store before launching the app. On the simulator this is a single command (no Settings UI, no trust toggle), and the proxy host is 127.0.0.1 — the simulator shares the host's loopback. See references/simulator-mitm-setup.md for the full flow (works for Burp Suite, Charles, mitmproxy, Proxyman, OWASP ZAP).
Frida on iOS Simulator (Frida 17+): Use the .implementation hook pattern and attach by PID. All simulator-specific gotchas, CLI syntax changes, and verified recipes are in references/frida-ios-simulator-workflow.md.
Simulator visibility: By default, the simulator launches in visible mode. Only use headless mode when explicitly requested by the user.
Simulator or physical device?
- Simulator (Frida 17+):
references/frida-ios-simulator-workflow.md
- Physical device (jailbroken):
references/frida-ios-guide.md
Reference: references/simforge-ios-testing.md for the complete workflow, internal architecture (LC_BUILD_VERSION patching, SIMCTL_CHILD_DYLD_INSERT_LIBRARIES injection, tmpfs overlays), use cases (Frida Gadget, Theos tweaks, URL scheme testing, SpringBoard patching), limitations, and troubleshooting. For deep dives, see references/simforge-emulation-flow.md (the canonical 10-step procedure with pre-flight checks), references/simforge-crash-triage.md (diagnostic methodology with decision tree by termination.namespace+indicator), and references/simforge-compatibility.md (FairPlay / Swift ABI / hardware capability matrix).
Unity games in the simulator (Metal heap crash): if a converted Unity (IL2CPP) game aborts at graphics init with MTLStorageModePrivate is required for heaps, inject the interposer dylib assets/dylibs/metalheapfix.m (one-command driver: scripts/unity_sim_metalfix.sh <UDID> <bundle-id>). Full methodology + IL2CPP reversing (Il2CppDumper on macOS) in references/unity-ios-security.md; triage entry in references/simforge-crash-triage.md.
Troubleshooting: Mixed Load Commands
If the app crashes immediately after simforge convert with dyld assertion or SIGSEGV:
otool -l Payload/YourApp.app/Frameworks/Suspect.framework/Suspect | grep -A3 "LC_VERSION_MIN\|LC_BUILD"
python3 scripts/simforge_cleanup.py Payload/YourApp.app
codesign -f -s - --all-architectures Payload/YourApp.app
xcrun simctl launch booted com.example.app
Why this happens: SimForge adds LC_BUILD_VERSION for simulator but doesn't remove the legacy LC_VERSION_MIN_IPHONEOS. Modern dyld rejects binaries with mixed version commands. See references/simforge-legacy-loadcmd-cleanup.md for detailed methodology.
Unity IL2CPP Simulator Fix (metalheapfix)
Critical: Unity 2021.x IL2CPP apps crash on the iOS Simulator due to MTLHeap using MTLStorageModeShared (valid on device, rejected by simulator's MTLSimDriver). This is NOT a code signing or packaging issue — it's a Metal driver incompatibility.
Symptom: App launches, immediately crashes with:
abort → __assert_rtn → Metal MTLReportFailure
MTLSimDriver -[MTLSimDevice newHeapWithDescriptor:]
UnityFramework MetalHeap::CreateHeap(MTLHeapDescriptor*)
Fix: A dylib that intercepts MTLCreateSystemDefaultDevice() via DYLD_INTERPOSE and swizzles -[MTLSimDevice newHeapWithDescriptor:] to return nil. This forces Unity to fall back to direct buffer allocation (device.newBufferWithLength:options:) which the simulator supports.
⚠️ WRONG APPROACH (don't repeat): Forcing descriptor.storageMode = MTLStorageModePrivate passes the heap assertion but crashes at buffer creation (MTLSimHeap newBufferWithLength: → XPC error) because Unity's scratch buffers need CPU write access and Private heaps are GPU-only. The correct fix is returning nil, not forcing Private.
Source (metalheapfix.m):
#import <Foundation/Foundation.h>
#import <Metal/Metal.h>
#import <objc/runtime.h>
static id<MTLDevice> (*orig_MTLCreaterSystemDefaultDevice)(void);
static dispatch_once_t onceToken;
static id swizzled_newHeapWithDescriptor(id self, SEL _cmd, MTLHeapDescriptor *descriptor) {
NSLog(@"[metalheapfix] newHeapWithDescriptor: -> returning nil (force non-heap path)");
return nil;
}
static void installSwizzle(id<MTLDevice> device) {
dispatch_once(&onceToken, ^{
Class cls = object_getClass(device);
Method original = class_getInstanceMethod(cls, @selector(newHeapWithDescriptor:));
if (original) {
method_setImplementation(original, (IMP)swizzled_newHeapWithDescriptor);
NSLog(@"[metalheapfix] installed heap swizzle on %s", class_getName(cls));
}
});
}
__attribute__((used))
static const struct { const char* name; void* replacement; void* original; } interpose_MTLCreaterSystemDefaultDevice
__attribute__((section("__DATA,__interpose"))) = {
"MTLCreateSystemDefaultDevice",
(void*)new_MTLCreaterSystemDefaultDevice,
(void*)&orig_MTLCreaterSystemDefaultDevice
};
Compile on TARGET machine (do NOT copy dylib from another machine):
SDK=$(xcrun --sdk iphonesimulator --show-sdk-path)
clang -dynamiclib -fobjc-arc -Wno-incompatible-function-pointer-types \
-isysroot "$SDK" -target arm64-apple-ios15.0-simulator \
-framework Foundation -framework Metal \
-o metalheapfix.dylib metalheapfix.m
codesign -f -s - metalheapfix.dylib
Complete Unity Simulator Workflow:
simforge convert /path/to/Payload/YourApp.app
codesign -f -s - YourApp.app/Frameworks/*
codesign -f -s - YourApp.app
codesign -v --strict YourApp.app
UDID=<your iOS 18+ simulator UDID>
xcrun simctl install $UDID YourApp.app
SIMCTL_CHILD_DYLD_INSERT_LIBRARIES="/path/to/metalheapfix.dylib" \
xcrun simctl launch $UDID com.example.app
xcrun simctl spawn $UDID launchctl list | grep -i appname
xcrun simctl io $UDID screenshot screenshot.png
⚠️ Runtime version matters: Test on the SAME iOS runtime that was verified. iOS 18.6 works. iOS 17.5 may NOT work — the MTLSimDriver behavior differs between runtimes and the swizzle may not prevent heap creation on older runtimes. ALWAYS check xcrun simctl list devices and match the runtime explicitly.
Combine with Frida: You can inject multiple dylibs by colon-separating: SIMCTL_CHILD_DYLD_INSERT_LIBRARIES="/path/to/metalheapfix.dylib:/path/to/frida-gadget.dylib"
Making it Permanent: Embedding the Dylib in the Bundle
The SIMCTL_CHILD_DYLD_INSERT_LIBRARIES approach only works per-launch via command line. To make the fix permanent (app launches by tapping the icon), embed the dylib inside the bundle:
Concept: Add an LC_LOAD_DYLIB load command to the Mach-O binary so dyld loads the dylib automatically at startup. This is the same technique used for Frida Gadget injection, bypass tweaks, and any permanent code modification.
┌─────────────────────────────────────┐
│ App.app/ │
│ ├── Binary (main executable) │ ← Add LC_LOAD_DYLIB here
│ ├── Frameworks/ │
│ │ ├── UnityFramework.framework/ │
│ │ ├── metalheapfix.dylib │ ← Copy dylib here
│ │ └── ... │
│ └── Info.plist │
└─────────────────────────────────────┘
Step-by-step:
cp metalheapfix.dylib App.app/Frameworks/
install_name_tool -id "@executable_path/Frameworks/metalheapfix.dylib" \
App.app/Frameworks/metalheapfix.dylib
pip install lief
python3 -c "
import lief
binary = lief.MachO.parse('App.app/YourBinary')
for b in binary.builders:
b.add(lief.MachO.DylibCommand.from_path('@executable_path/Frameworks/metalheapfix.dylib'))
b.write('App.app/YourBinary')
break
"
insert_dylib --strip-codesig --all-yes \
@executable_path/Frameworks/metalheapfix.dylib App.app/YourBinary
optool install -c load -p @executable_path/Frameworks/metalheapfix.dylib \
-t App.app/YourBinary
codesign -f -s - App.app/Frameworks/metalheapfix.dylib
codesign -f -s - App.app/Frameworks/*
codesign -f -s - App.app
codesign -v --strict App.app
xcrun simctl install $UDID App.app
xcrun simctl launch $UDID com.example.app
Unity note: The main binary is a thin stub (~85KB). Adding LC_LOAD_DYLIB to the stub is sufficient — dyld processes DYLD_INTERPOSE globally regardless of which binary triggered the load. If it doesn't work, also add the load command to UnityFramework.framework/UnityFramework.
This technique applies to ANY dylib injection: Frida Gadget, SSL pinning bypass, jailbreak detection bypass, custom tweaks — the process is identical.
Frida iOS Integration
Frida Installation on macOS (Python 3.14+): macOS with Homebrew Python 3.14+ has PEP 668 enabled, which blocks global pip installs. See references/tool-installation-ios.md for complete troubleshooting.
brew install pipx
pipx install frida-tools
export PATH="$HOME/.local/bin:$PATH"
python3 -m pip install --break-system-packages frida frida-tools
python3 -m pip install --user frida frida-tools
export PATH="$HOME/Library/Python/3.14/bin:$PATH"
frida --version
Simulator Workflow (Frida 17+)
UDID=$(xcrun simctl list devices booted | grep -oE "[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}")
xcrun simctl launch booted com.example.app
sleep 2
PID=$(xcrun simctl spawn booted launchctl list 2>/dev/null | rg "com.example.app" | awk '{print $1}' || ps aux | rg "com.example.app" | awk '{print $2}')
frida -D $UDID -p $PID -l script.js
Syscall Hook Limitations: On simulator, C-level syscall hooks (stat(), fopen(), fork(), posix_spawn()) may fail. Use ObjC method hooks via .implementation pattern instead. See references/frida-ios-simulator-workflow.md for complete patterns and limitations.
Device Workflow (Jailbroken)
-U = USB device (jailbroken physical device with frida-server running). For simulator, use -D <SIMULATOR_UDID> instead — see Simulator Workflow below.
Gotcha: frida-ps -U works without jailbreak (uses lockdownd API), but frida -U -p / frida -U -f require jailbreak or Frida Gadget. If attach fails with "need Gadget to attach on jailed iOS", the device is not jailbroken — see references/troubleshooting-ios.md for solutions (SimForge, Gadget injection).
frida -U -f com.example.app -l script.js
frida -U com.example.app -l script.js
Frida for iOS
if (ObjC.available) {
console.log("Objective-C runtime available");
console.log(ObjC.classes);
} else {
console.log("Objective-C runtime not available");
}
Reference: bundled Frida scripts in assets/frida-scripts/. See references/frida-scripts-index.md for the canonical catalog.
Focused runtime triage: use pasteboard-monitor.js for clipboard visibility, xpc-tracer.js for XPC/native boundary discovery, and url-scheme-monitor.js for URL scheme logging.
Script Maturity Levels:
- STABLE: Production-ready (
ssl-pinning-bypass-ios.js, jailbreak-detection-bypass.js, biometric-bypass-ios.js, network-interceptor-ios.js, etc.)
- BETA: Functional but incomplete — use with caution
Objection iOS Commands
objection -g com.example.app explore
ios hooking list classes
ios jailbreak disable
ios sslpinning disable
ios keychain dump
ios biometrics bypass
ios pasteboard monitor
ios userdefaults get
iOS Runtime Testing
xcrun simctl openurl booted "scheme://host/path?param=value"
idevicesyslog | rg com.example.app
log stream --predicate 'process == "YourApp"' | rg com.example.app
Test URL Scheme Payload
myapp://deeplink?param=<script>alert(1)</script>
SSL Pinning bypass: references/ssl-pinning-bypass-ios.md + assets/frida-scripts/ssl-pinning-bypass-ios.js
Anti-tamper bypass: references/runtime-integrity-bypass.md + assets/frida-scripts/jailbreak-detection-bypass.js (comprehensive: ObjC file/URL/write-test checks + stat/fopen/fork/posix_spawn/dlopen syscalls + direct isJailbroken/jailbreakTest method discovery) for anti-debug, anti-frida, and jailbreak detection bypass. For a quick, low-noise pass on apps that only call isJailbroken-style methods (or when the C-level hooks destabilize the target), use the lightweight assets/frida-scripts/jailbreak-bypass-ios.js instead. For simulator work, prefer jailbreak-bypass-ios.js — it uses the .implementation pattern required by Frida 17+ on the simulator (see references/frida-ios-simulator-workflow.md).
RASP bypass:
- Comprehensive guide:
references/rasp-guide-ios.md + assets/frida-scripts/rasp-bypass-ios.js — 15 RASP solutions (FreeRASP, IOSSecuritySuite, JailMonkey, plus 12 commercial: Arxan/Digital.ai, Guardsquare, Promon SHIELD, Appdome, Irdeto, WhiteCryption, Verimatrix, Zimperium, IBM Trusteer, Pradeo, V-Key, Build38). Includes detection methods, weaknesses, and bypass techniques for each.
- Reusable patterns:
references/rasp-patterns-ios.md — Generic RASP bypass patterns (dylib injection, SimForge complete conversion, framework stub creation, Frida 17+ simulator patterns, white screen diagnosis). Applicable to any iOS app.
- Framework stub guide:
references/rasp-framework-stub-guide.md — How to create Objective-C framework stubs for simulator compatibility (NuDetectSDK, IOSSecuritySuite, FreeRASP templates included)
Debugger detection: references/debugger-detection-bypass.md for sysctl P_TRACED, ptrace PT_DENY_ATTACH, getppid() checks and Frida Interceptor bypasses.
Secure Enclave probing: references/secure-enclave-testing.md + assets/frida-scripts/secure-enclave-probe.js.
iCloud Private Relay testing: references/icloud-private-relay-testing.md for relay-aware network captures.
Enterprise / MDM bypass: assets/frida-scripts/mdm-bypass.js and assets/frida-scripts/enterprise-cert-bypass.js for managed-device restrictions and enterprise certificate trust.
Jailbreak setup: references/jailbreak-setup-guide.md for the supported iOS versions and current checkra1n / palera1n / Dopamine coverage.
Frida server installation: references/frida-server-ios-install.md for step-by-step Frida server setup on jailbroken devices.
Frida on iOS (full guide): references/frida-ios-guide.md for installation, gadget mode, spawn vs attach.
Objection (full guide): references/objection-ios-guide.md for non-Frida interactive exploration.
Reference: references/libimobiledevice-guide.md for device pairing, syslog, backup, screenshot, and IPA installation commands.
Phase 5 — Classification and Reporting
Confidence Levels
| Level | Definition | Example Evidence |
|---|
| Confirmed | Full source-to-sink trace validated | Direct call chain from URL scheme source to WKWebView.evaluateJavaScript() with no sanitization |
| Likely | Strong evidence, minor gaps | Static trace clear but reflection obscures final sink |
| Needs Dynamic Confirmation | Static analysis inconclusive | Obfuscated code or native boundary requiring runtime verification |
Severity
Use CVSS 4.0. See references/cvss-scoring-ios.md for complete methodology, iOS-specific examples, and severity mapping. See references/cvss-examples-ios.md for 10 worked examples (ATS bypass, keychain exposure, URL scheme hijack, jailbreak bypass, biometric bypass, etc.).
Finding Template
## [ID] - [Title]
**Confidence**: [Confirmed/Likely/Needs Dynamic Confirmation]
**Severity**: [Critical/High/Medium/Low] (CVSS: [X.X])
**CWE**: [CWE-ID]
**OWASP**: [OWASP Category]
### Description
[1-2 sentences explaining what the vulnerability is]
### Affected Components
- **File**: `path/to/file.m` or `path/to/ViewController.swift`
- **Method**: `methodName` or `@objc func methodName()`
- **Component**: `[ViewController/Service/Extension]` (if applicable)
### Attack Scenario
1. Attacker [action, e.g., crafts malicious URL scheme with payload]
2. App [processing step, e.g., extracts parameter without validation]
3. Data propagates through [call chain]
4. Reaches sink [dangerous operation]
5. Results in [impact, e.g., arbitrary JavaScript execution in WebView context, data exfiltration, or credential theft]
### Proof of Concept
```bash
# Example: URL scheme path traversal
xcrun simctl openurl booted "myapp://deeplink?path=../../../../etc/passwd"
```
Or provide Frida hook script for dynamic verification:
```javascript
// Hook vulnerable method
const targetClass = ObjC.classes.MyViewController;
if (targetClass) {
const method = targetClass['- processURL:'];
if (method) {
Interceptor.attach(method.implementation, {
onEnter: function(args) {
console.log("URL processed: " + ObjC.Object(args[2]));
}
});
}
}
```
### Impact
- **Confidentiality**: [High/Medium/Low/None] — [explanation]
- **Integrity**: [High/Medium/Low/None] — [explanation]
- **Availability**: [High/Medium/Low/None] — [explanation]
### Remediation
```swift
// Provide secure code example
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
// Parse URL query parameters safely using URLComponents
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let queryItems = components.queryItems,
let input = queryItems.first(where: { $0.name == "path" })?.value,
isValidPath(input) else {
os_log("Invalid path detected")
return false
}
loadContent(at: input)
return true
}
private func isValidPath(_ path: String) -> Bool {
// Prevent path traversal and validate format
return !path.contains("..") && path.range(of: "^/safe/[a-zA-Z0-9_]+\\.html$", options: .regularExpression) != nil
}
```
Or Objective-C:
```objc
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
// NSURL has no -queryParameterValue: method. Use NSURLComponents + NSURLQueryItem.
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
if (!components) return NO; // Invalid URL
NSArray<NSURLQueryItem *> *queryItems = components.queryItems;
NSString *input = nil;
for (NSURLQueryItem *item in queryItems) {
if ([item.name isEqualToString:@"path"]) {
input = item.value;
break;
}
}
if ([self isValidPath:input]) {
[self loadContentAtPath:input];
} else {
NSLog(@"Invalid path detected");
return NO;
}
return YES;
}
```
### CVSS 4.0 Calculation
[Show vector string and score breakdown]
Coverage Statement
End your report with:
Coverage Analysis:
- Static Analysis: Complete (all decompiled sources analyzed)
- Dynamic Analysis: [Complete/Partial/Not Performed] (reason if partial)
- Scope: [com.example.app.* bundle only]
- Framework: [React Native/Flutter/Native/Standard]
- Obfuscation: [Swift Obfuscator/Custom/None]
Limitations:
- [List any limitations, e.g., "Native code analysis requires additional tools"]
- [Any components that could not be analyzed]
- [Any findings requiring additional verification]
Total Findings: X (Critical: Y, High: Z, Medium: A, Low: B)
Reference: references/reporting-templates-ios.md for executive summary format, remediation priority matrix, and presentation templates.
Automated Report Generation
Use the generate-report.py script to generate professional HTML or Markdown reports from findings JSON:
python3 scripts/generate-report.py \
--input findings.json \
--output report.html \
--app-name "My App" \
--bundle-id "com.example.app"
python3 scripts/generate-report.py \
--input findings.json \
--output report.md \
--app-name "My App" \
--bundle-id "com.example.app"
The script supports both JSON array format and JSONL (one finding per line) and automatically:
- Sorts findings by severity (Critical first)
- Calculates CVSS 4.0 severity scores
- Generates executive summary with risk rating
- Maps OWASP MASTG categories
- Provides formatted proof of concept and remediation sections
See scripts/test-findings.json for the expected JSON structure.
Reference: references/reporting-templates-ios.md for the full executive-summary format, remediation priority matrix, and presentation slide templates.
Reference: references/owasp-mastg-ios-checklist.md for the full MASTG test catalog (use it to make sure every applicable test has been run before signing off the report).
Reference: references/ios-privacy-testing.md for the privacy/ATT/Privacy Manifest section of the report.
IPA Modification Workflow
0. Optional: Convert for simulator testing (Apple Silicon)
Before any modification, if you intend to test the app in the iOS simulator instead of a physical device, run simforge convert to patch the Mach-O LC_BUILD_VERSION to PLATFORM_IOSSIMULATOR. This breaks the original code signature, so re-sign (step 3) becomes mandatory.
simforge convert /path/to/Payload/YourApp.app
Reference: references/simforge-ios-testing.md for the full simulator-based modification + dylib injection flow.
1. Extract
unzip app.ipa -d app-extracted/
cd app-extracted/Payload/YourApp.app/
2. Modify
Binary Patching
Use tools like otool, jtool2, or hex editor to patch binary:
jtool2 -d YourApp > disassembly.txt
Resource Modification
Edit Info.plist or embedded resources:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
3. Re-sign
codesign --remove-signature YourApp.app
cp YourProfile.mobileprovision YourApp.app/embedded.mobileprovision
codesign -f -s "iPhone Distribution: Your Team" \
--entitlements entitlements.plist \
YourApp.app
codesign -dvv YourApp.app
4. Re-package
cd ../../
zip -r app-modified.ipa Payload/
5. Install and Verify
ideviceinstaller install app-modified.ipa
cd app-extracted/Payload && xcrun simctl install booted YourApp.app
Reference: references/dynamic-analysis-setup-ios.md for advanced repackaging, code signing, and installation. See references/repackaging-ios-guide.md for binary patching edge cases and troubleshooting.
Troubleshooting
Encrypted Binary
otool -l YourApp | rg -A 10 "LC_ENCRYPTION_INFO(_64)?"
Frida Cannot Attach
otool -l YourApp | rg LC_CODE_SIGNATURE
codesign -d --entitlements - YourApp.app/YourApp
frida -U -f com.example.app -l assets/frida-scripts/jailbreak-detection-bypass.js
Obfuscated Swift Code Unreadable
- Identify obfuscation:
dsdump YourApp | head -50
- Use SwiftDemangle:
swift-demangle <mangled_symbol>
- See
references/static-analysis-patterns-ios.md → "Obfuscation Patterns"
- Switch to Phase 4 for runtime behavior
When to Escalate to Dynamic Analysis
Static analysis reaches limits when: obfuscation unclear, reflection, native boundaries, anti-debug/jailbreak detection, SSL pinning. → Proceed to Phase 4 using references/dynamic-analysis-setup-ios.md.
Examples
Example 1: Quick IPA Assessment
User says: "Audit this IPA com.example.app.ipa"
Actions:
- Extract IPA:
unzip app.ipa -d extracted/
- Detect framework:
otool -l YourApp | rg "LC_ENCRYPTION_INFO"
- Analyze Info.plist:
plutil -p Info.plist
- Search for secrets:
strings YourApp | rg -i "password|key|secret"
- Generate CVSS report using methodology in Phase 5
Result: Complete security assessment with vulnerability findings
Example 2: SSL Pinning Bypass
User says: "Bypass SSL pinning in target.app"
Actions:
- Attach Frida:
frida -U -f com.example.app -l ssl-pinning-bypass-ios.js
- If fails, consult
references/ssl-pinning-bypass-ios.md
- Verify network traffic is unencrypted
Result: App accepts all certificates, enabling MITM testing
Example 3: IPA Modification and Testing
User says: "Modify this IPA to disable jailbreak detection"
Actions:
- Extract IPA:
unzip app.ipa -d extracted/
- Patch binary using
jtool2 or hex editor
- Re-sign:
codesign -f -s - YourApp.app
- Re-package:
zip -r app-modified.ipa Payload/
- Install:
ideviceinstaller install app-modified.ipa
Result: Modified IPA that bypasses jailbreak detection
Example 4: URL Scheme Abuse Testing
User says: "Test URL schemes in myapp.ipa for vulnerabilities"
Actions:
- Extract schemes from Info.plist:
plutil -p Info.plist | grep CFBundleURLSchemes
- Analyze handlers: Check
application(_:open:options:) implementation
- Test with Frida:
frida -D $UDID -p $PID -l url-scheme-monitor.js
- Fuzz schemes:
xcrun simctl openurl booted "myapp://payload"
Result: List of vulnerable URL schemes with PoC payloads
Example 5: Jailbreak Detection Bypass (Simulator)
User says: "Run this app in simulator and bypass jailbreak detection"
Actions:
- Get simulator UDID:
UDID=$(xcrun simctl list devices booted | grep -oE "[A-F0-9-]{36}" | head -1)
- Launch app:
xcrun simctl launch booted com.example.app
- Get PID:
PID=$(xcrun simctl spawn booted launchctl list | rg "com.example.app" | awk '{print $1}')
- Attach with bypass:
frida -D $UDID -p $PID -l jailbreak-bypass-ios.js
Result: App runs in simulator without jailbreak restrictions
Real-World Vulnerability Patterns
Patterns discovered from disclosed vulnerability reports (HackerOne) that are NOT covered by standard testing methodologies. These represent gaps where mobile apps deviate from web security assumptions.
Pattern 1: Rate Limiting Bypass on Mobile Endpoints
Vulnerability: Authentication endpoints on mobile often lack rate limiting, even when web equivalents enforce lockouts.
Real Case: H1-160109 (Instacart iOS) - Web locked after 15 attempts, mobile allowed 50+ password guesses without restrictions. H1-2245437 (Files iOS) - PIN code with unlimited attempts.
Detection with this skill:
rg "oauth|login|token|pin" -g "*.m" -g "*.swift"
frida -U -f com.example.app -l assets/frida-scripts/mobile-rate-limit-detector-ios.js
Expected Finding:
[VULN] 50 attempts to /oauth/token
NO rate limiting detected after 50 requests
Reference: H1-160109 (Instacart iOS), H1-2245437 (Files iOS)
Impact: Brute force possible, account takeover risk HIGH
PoC:
for (let i = 0; i < 50; i++) {
}
Remediation:
private let maxAttempts = 5
private let lockoutTime: TimeInterval = 300
func attemptLogin() {
guard attemptCount < maxAttempts else {
return
}
attemptCount += 1
}
Related Script: assets/frida-scripts/mobile-rate-limit-detector-ios.js
Pattern 2: WebView XSS via Unsanitized HTML
Vulnerability: WebViews loading HTML content without sanitization, especially when HTML contains user input or template literals.
Real Cases: H1-575562 (Nextcloud iOS) - Blind XSS via unsanitized file content; H1-991713, 993670, 1436558, 1438028 (Brave iOS) - Multiple XSS vectors through WebView HTML injection.
Detection with this skill:
frida -U -f com.example.app -l assets/frida-scripts/webview-xss-scanner-ios.js
Expected Finding:
[VULN] Unsanitized HTML loading detected in WebView
Pattern: {{username}}
Type: template
Impact: XSS possible if attacker controls HTML source
Reference: H1-575562 (Nextcloud WebView XSS)
PoC:
Remediation:
func loadSafeHTML(_ html: String, baseURL: URL) {
let sanitized = html
.replacingOccurrences(of: "<script", with: "<script")
.replacingOccurrences(of: "{{", with: "")
.replacingOccurrences(of: "${", with: "")
webView.loadHTMLString(sanitized, baseURL: baseURL)
}
Related Script: assets/frida-scripts/webview-xss-scanner-ios.js
Pattern 3: Deep Link CSRF (Missing Token Validation)
Vulnerability: State-changing deep links lack CSRF tokens, allowing attackers to trigger actions on behalf of users.
Real Case: H1-805073 (Periscope iOS) - pscp://user/<id>/follow could be triggered from any context without CSRF token, allowing forced follows and account takeover.
Detection with this skill:
frida -U -f com.example.app -l assets/frida-scripts/deeplink-csrf-validator-ios.js
xcrun simctl openurl booted "myapp://follow?user=victim"
Expected Finding:
[VULN] Sensitive action via deep link WITHOUT CSRF token
URL: myapp://follow?user=victim
Action: follow
Impact: CSRF possible - forced action without user consent
Reference: H1-805073 (Periscope deep link CSRF)
PoC:
<a href="myapp://follow?user=attacker">Click for prize!</a>
Remediation:
func processDeepLink(_ url: URL) {
guard let token = url.queryParameters?["token"],
validateCSRFToken(token) else {
return
}
}
Related Script: assets/frida-scripts/deeplink-csrf-validator-ios.js
Pattern 4: Missing SSL Certificate Validation
Vulnerability: Apps that don't validate SSL/TLS certificates are vulnerable to MITM attacks without any bypass needed.
Real Case: H1-168538 (Twitter iOS 6.62-6.62.1) - Did not validate SSL certificates. A transparent proxy was sufficient to intercept traffic and extract OAuth tokens without installing a trusted CA certificate.
Detection with this skill:
frida -U -f com.example.app -l assets/frida-scripts/ssl-validation-checker-ios.js
Expected Finding:
[!] CRITICAL VULNERABILITY
[!] App does NOT validate SSL certificates!
[!] MITM attacks possible WITHOUT any bypass needed
[!] Reference: H1-168538 (Twitter iOS cert validation bypass)
PoC:
mitmproxy --listen-port 8080
Remediation:
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let serverTrust = challenge.protectionSpace.serverTrust!
let credential = URLCredential(trust: serverTrust)
completionHandler(.useCredential, credential)
}
Related Script: assets/frida-scripts/ssl-validation-checker-ios.js
Pattern 5: Biometric Deeplink Bypass
Vulnerability: Deep links navigate to protected features without requiring biometric re-authentication when app is already unlocked.
Real Case: H1-637194 (Shopify Mobile) - When app was open, deep links could bypass fingerprint authentication and directly access protected features like settings/payment.
Detection with this skill:
frida -U -f com.example.app -l assets/frida-scripts/biometric-deeplink-bypass-ios.js
xcrun simctl openurl booted "myapp://settings"
Expected Finding:
[VULN] Protected view accessed WITHOUT recent biometric
View: SettingsViewController
Biometric was 15000ms ago
Deep link was 2000ms ago
Reference: H1-637194 (Shopify deeplink bypass)
PoC:
Remediation:
var lastBiometricAuth: Date?
func navigateToProtectedFeature() {
let timeout: TimeInterval = 5.0
if let lastAuth = lastBiometricAuth,
Date().timeIntervalSince(lastAuth) < timeout {
showProtectedFeature()
} else {
requestBiometric { success in
if success { showProtectedFeature() }
}
}
}
Related Script: assets/frida-scripts/biometric-deeplink-bypass-ios.js
Troubleshooting
Encrypted Binary (FairPlay)
Error: LC_ENCRYPTION_INFO cryptid 1 - binary cannot be analyzed
Cause: App Store FairPlay encryption
Solution: Decrypt with frida-ios-dump, Clutch, or bagbak on a jailbroken device. See references/macho-binary-analysis.md §Encryption.
Frida Cannot Attach
Error: "Failed to attach", "Process not found", or immediate disconnect
Cause: Ptrace protection, anti-debug, or app crashed
Solution:
otool -l YourApp | rg LC_CODE_SIGNATURE
codesign -d --entitlements - YourApp.app/YourApp
frida -U -f com.example.app -l assets/frida-scripts/jailbreak-detection-bypass.js
Obfuscated Swift Code Unreadable
Error: dsdump shows unreadable or mangled symbols
Cause: Swift obfuscation
Solution:
swift-demangle <mangled_symbol>
Info.plist Cannot Parse
Error: "Cannot parse plist" or plutil fails
Cause: Corrupted or binary plist format
Solution:
plutil -convert xml1 Info.plist -o -
plutil -convert binary1 Info.plist -o
Class Dump Fails
Error: dsdump or class-dump produces no output
Cause: Binary stripped, protected, or not Mach-O
Solution:
lipo -info YourApp
Quick Device Verification Checklist
idevice_id -l
ideviceinfo | grep -E "^(DeviceName|ProductVersion|ProductType|ModelNumber|CPUArchitecture|SerialNumber)"
idevicepair validate
ideviceinstaller list
ideviceinstaller list --all
frida-ps -U | head -5
frida-ps -Uai | head -15
Device Not Found
Error: "No device found" or idevice commands fail
Cause: Device not connected, usbmuxd not running, or driver issue
Solution:
idevice_id -l
sudo launchctl stop com.apple.usbmuxd && sudo launchctl start com.apple.usbmuxd
Simulator App Crashes Immediately
Error: App launches but crashes before main()
Cause: FairPlay encrypted, code signature invalid, or incompatible platform
Solution: See simforge-crash-triage.md for decision tree. Verify:
otool -l YourApp | rg -A 4 LC_ENCRYPTION
codesign -v --strict YourApp
otool -l YourApp | rg -A 4 LC_BUILD_VERSION
Jailbreak Detection Persists
Error: App still detects jailbreak after bypass attempts
Cause: Multiple detection points, custom checks, or server-side validation
Solution: Use comprehensive bypass in assets/frida-scripts/jailbreak-detection-bypass.js. See references/jailbreak-detection-bypass-ios.md for full methodology.
For comprehensive troubleshooting, see references/troubleshooting-ios.md for detailed diagnosis of toolchain issues, environment problems, and common failure patterns.
CI/CD and DevSecOps Integration
When integrating iOS security testing into CI/CD pipelines or automating security checks in development workflows, consider these tools and practices:
CI/CD Platform Security
- GitHub Actions: See
references/github-actions-ios-security.md for secure workflow patterns, secrets management, and artifact handling in iOS projects.
- Fastlane: See
references/fastlane-security.md for secure automation, lane hardening, and credential protection in iOS build/deploy pipelines.
- General CI/CD: See
references/ci-cd-integration-ios.md for integrating automated security testing into any CI/CD platform (Jenkins, GitLab CI, CircleCI, etc.).
Automation Scripts
The scripts/ directory includes automation-friendly tools:
scripts/auto-audit-static-ios.sh — One-shot static analysis driver for Phases 0–3
scripts/sbom_generator.py — Generate SBOMs for supply chain security
scripts/dependency_scanner.py — Scan dependencies for CVEs and license compliance
scripts/generate-report.py — Generate reports from findings JSON
See references/automation-scripts-ios.md for complete automation workflow integration.
References Index
| Phase | Files |
|---|
| Start | getting-started-ios, troubleshooting-ios, tool-versions, frida-dynamic-analysis-ios |
| 0 | environment-setup-ios, tool-installation-ios, static-analysis-patterns-ios, macho-binary-analysis, framework-detection-ios, ipa-extraction-guide, mobsf-integration-guide, advanced-tools-ios, bitcode-analysis, libimobiledevice-guide |
| 1 | info-plist-checklist, entitlements-security-guide, ios-version-security-changes, app-extensions-security, url-scheme-security-guide, universal-links-guide, ats-configuration-guide, privacy-manifest-ios, app-groups-security |
| 2 | commoncrypto-analysis, keychain-security-guide, userdefaults-security, coredata-security, pasteboard-security, data-protection-api-guide, objc-security-patterns, swift-security-patterns, side-channel-analysis-ios, memory-analysis-ios |
| 3 | url-scheme-security-guide, deep-link-exploitation-ios, app-groups-security, xpc-services-security, ipc-xpc-guide, webview-security-ios, notification-security, phishing-attacks-ios |
| 4 | jailbreak-setup-guide, jailbreak-detection-bypass-ios, frida-server-ios-install, frida-ios-guide, frida-ios-simulator-workflow, objection-ios-guide, ssl-pinning-bypass-ios, dynamic-analysis-setup-ios, debugger-detection-bypass, runtime-integrity-bypass, secure-enclave-testing, icloud-private-relay-testing, libimobiledevice-guide, simforge-ios-testing, simforge-emulation-flow, simforge-crash-triage, simforge-compatibility, simforge-scripts-index, simulator-mitm-setup |
| 5 | cvss-scoring-ios, reporting-templates-ios, owasp-mastg-ios-checklist, ios-privacy-testing, cvss-examples-ios, frida-scripts-index, runtime-hardening-checks-ios |
| Mod | repackaging-ios-guide, obfuscation-detection-ios, bitcode-analysis |
| FW | react-native-ios-security, flutter-ios-security, cordova-ios-security, xamarin-ios-security, unity-ios-security, swiftui-security-deep-dive, core-ml-security, core-ml-security-expanded |
| Tools | advanced-tools-ios, environment-setup-ios, tool-installation-ios, tool-versions, linux-ios-analysis-workarounds |
| CI | automation-scripts-ios, ci-cd-integration-ios, github-actions-ios-security, fastlane-security |
| Cross | ios-version-security-changes, objc-security-patterns, swift-security-patterns |
| SC | sbom-supply-chain-guide, third-party-sdk-analysis |
| Ent | enterprise-app-testing, mdm-security-testing, configuration-profile-abuse |