MobSF
MobSF (Mobile Security Framework) is an automated static-analysis platform for iOS (and Android) apps. Feed it an IPA and it produces a report covering permissions, hardcoded secrets, insecure API usage, transport security, and more. It is the first pass before you start manual and dynamic testing.
Install and Run
Docker is the cleanest option:
docker pull opensecurity/mobile-security-framework-mobsf
docker run -it --rm -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
Run it in the background and persist the scan database:
docker run -d --name mobsf -p 8000:8000 \
-v mobsf_data:/root/.MobSF \
opensecurity/mobile-security-framework-mobsf:latest
# Logs if needed
docker logs -f mobsf
Local install (macOS/Linux, Python 3.8+):
git clone https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
cd Mobile-Security-Framework-MobSF
./setup.sh
./run.sh # serves on http://127.0.0.1:8000
Access the web UI at http://127.0.0.1:8000. Default credentials on the Docker image are mobsf / mobsf (change them for shared environments).
Getting an IPA to Analyze
MobSF needs a signed, unencrypted IPA. Sources:
- App Store apps are encrypted; decrypt first (e.g.,
frida-ios-dumpon a jailbroken device). - Ad-hoc/distribution builds you have on disk work as-is.
- Pull a copy off the device:
ideviceinstaller -l # find the bundle id
ideviceinstaller -o copy -i com.example.app # copy the IPA to the host (when supported)
# Or grab it over SSH on a jailbroken device
ssh root@localhost -p 2222 'find / -name "*.app" -maxdepth 6'
Running a Scan
Two ways to trigger a scan:
- Web UI: upload the IPA in the "Upload" box, then open "Start Dynamic Analysis" only if you have a device/emulator configured.
- REST API: useful for CI and for scripting batch uploads.
# REST API scan (API key in Settings > API Key)
curl -F "file=@app.ipa" \
-H "Authorization: <API-KEY>" \
http://127.0.0.1:8000/api/v1/upload
# Poll for results with the returned hash
curl http://127.0.0.1:8000/api/v1/report/<hash> -H "Authorization: <API-KEY>"
What the Report Covers
The static report is organized into sections; this is what to look for on iOS:
- App basics: bundle ID, version, entitlements (this reveals debug flags and keychain groups).
- Permissions: every
NSCameraUsageDescription, location, contacts, etc. Compare against what the app actually needs. - Hardcoded secrets: API keys, tokens, passwords, AWS keys found in the binary and resources.
- Insecure APIs: weak crypto (MD5, SHA1, DES, RC4), use of
UIWebView, insecureNSUserDefaultskeys. - Transport security: ATS configuration (
NSAppTransportSecurity), the presence ofNSAllowsArbitraryLoads, and whether HTTPS is used for network calls. - Binary analysis: obfuscation level, symbol stripping, dylib loading (spot Frida/objection gadgets accidentally left in production builds).
- iOS specifics: insecure keychain usage, missing data protection, and the presence of known vulnerable library versions.
Workflow: MobSF + Manual Testing
1. Upload the IPA -> read the static report (secrets, permissions, endpoints).
2. Cross-reference findings with Burp history while you run the app.
3. Investigate flagged items dynamically (e.g., a hardcoded key used in a request).
4. Patch and re-scan after changes to confirm fixes.
A typical fast loop: static scan while you set up the proxy and device, then validate each static finding against real traffic.
Gotchas
- The Docker container is ephemeral with
--rm; persist~/.MobSF(themobsf_datavolume above) or you lose scan history. - MobSF analyzes the binary and resources, not runtime behavior — combine it with Frida/objection and Burp for dynamic coverage.
- Encrypted IPAs produce partial or confusing results; decrypt before uploading.
- On iOS 17+ builds, some hardcoded-secret detections are noisier; triage flags by evidence in the code context panel.
- API key and default creds are findings in a shared lab — restrict access to
127.0.0.1unless you really need network exposure.
Quick Command Summary
# Docker run
docker run -it --rm -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
# Local run
./setup.sh && ./run.sh
# API upload
curl -F "file=@app.ipa" -H "Authorization: <API-KEY>" http://127.0.0.1:8000/api/v1/upload