Mobile Security Framework (MobSF) is an open-source, automated, all-in-one mobile application penetration testing, malware analysis, and security assessment framework. It is written in Python 3 and is developed and maintained by Ajin Abraham and the MobSF community. MobSF is capable of performing both static analysis and dynamic analysis on Android (APK, XAPK, source code ZIP), iOS (IPA, source code ZIP), and Windows (APPX) application binaries.
MobSF exposes a browser-based web interface (by default at http://127.0.0.1:8000) that a tester uses to upload a mobile application file, after which MobSF automatically:
- Extracts the application and decompiles it (using apktool, dex2jar/jadx, and other bundled utilities internally).
- Parses the AndroidManifest.xml (or Info.plist for iOS) to enumerate permissions, exported components, and activities.
- Scans decompiled source code for insecure coding patterns (hardcoded secrets, weak cryptography, insecure WebView configurations, improper certificate validation, and more) using its own rule engine.
- Performs a malware/reputation check on embedded trackers, domains, and API endpoints.
- Generates a security score and a full PDF/HTML report with CVSS-style findings.
- Optionally performs Dynamic Analysis using a connected Android emulator/device (with Frida integrated under the hood) to observe runtime behavior, API calls, and network traffic.
MobSF also ships a REST API, which allows the entire scan lifecycle (upload, scan, generate report, delete scan) to be automated from the command line or integrated into a CI/CD pipeline, which is the primary way this chapter demonstrates “command-line” usage of what is fundamentally a web application.
How to Install
MobSF can be installed on Kali Linux using either Docker (recommended, fastest, most reliable) or a manual source installation using a Python virtual environment.
Method 1 – Docker (Recommended)
# Update package lists
sudo apt update
# Install Docker if not already installed
sudo apt install docker.io -y
# Start and enable the Docker service
sudo systemctl start docker
sudo systemctl enable docker
# Pull the official MobSF image
sudo docker pull opensecurity/mobile-security-framework-mobsf:latest
# Run MobSF, exposing port 8000
sudo docker run -it --rm -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
Method 2 – Manual Installation from Source
# Install build dependencies
sudo apt install python3-dev python3-venv python3-pip build-essential \
libffi-dev libssl-dev libxml2-dev libxslt1-dev libjpeg62-turbo-dev \
zlib1g-dev wkhtmltopdf git -y
# Clone the MobSF repository
git clone https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
cd Mobile-Security-Framework-MobSF
# Run the setup script (Linux/Kali)
./setup.sh
# Start the MobSF server
./run.sh
After either method completes, open a browser and navigate to http://127.0.0.1:8000. The default login credentials in older versions were mobsf/mobsf; current versions generate a random username/password on first run and print it to the console/log — always check the terminal output for the actual credentials.
Syntax
MobSF itself is not a traditional single-binary CLI tool; it is operated primarily through its web UI or its REST API. The general syntax patterns used throughout this section are:
# Running the server
./run.sh [IP:PORT]
# Interacting with the REST API using curl
curl -X POST --url <MobSF_URL>/api/v1/<endpoint> \
-H "Authorization:<api_key>" \
[-F 'file=@<path_to_apk>'] \
[-d "<key>=<value>&<key2>=<value2>"]
All Command-Line Options / API Endpoints
run.sh script options:
| Option | Description |
|---|---|
./run.sh | Starts MobSF on default 127.0.0.1:8000 |
./run.sh 0.0.0.0:8000 | Binds MobSF to all interfaces on port 8000 |
./run.sh 127.0.0.1:8080 | Runs MobSF on a custom port |
Core REST API endpoints (used with curl -H "Authorization:<api_key>"):
| Endpoint | Method | Purpose |
|---|---|---|
/api/v1/upload | POST | Upload an APK/IPA/APPX/ZIP file for analysis |
/api/v1/scan | POST | Trigger a static scan on an uploaded file’s hash |
/api/v1/scan_logs | POST | Retrieve live scan logs for a hash |
/api/v1/report_json | POST | Retrieve the full static analysis report in JSON |
/api/v1/download_pdf | POST | Download the report as a PDF |
/api/v1/pdf | POST | Alternate PDF report generation endpoint |
/api/v1/scorecard | POST | Retrieve a simplified security scorecard |
/api/v1/delete_scan | POST | Delete a scan and its associated report/data |
/api/v1/recent_scans | GET | List recently scanned applications |
/api/v1/view_source | POST | Retrieve source code of a specific file in the report |
/api/v1/search | GET | Search scans by app name, package, or hash |
/api/v1/compare | GET | Compare two scan reports (diff) |
/api/v1/android/dynamic_analyzer | POST | Start Android dynamic analysis on a connected device |
/api/v1/dynamic/report_json | POST | Retrieve dynamic analysis report in JSON |
/api/v1/frida/instrument | POST | Instrument the app with Frida during dynamic analysis |
/api/v1/frida/api_monitor | POST | Enable Frida-based API monitoring |
/api/v1/scan_binary | POST | Perform binary-level scan (e.g., .so, .dylib) |
The full, always up-to-date API reference is available from any running instance at <MobSF_URL>/api_docs, and the API key is displayed on that same page and in the server console logs.
Basic Usage (Expected Output in Bash)
Starting MobSF via Docker:
$ sudo docker run -it --rm -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
[INFO] Creating MobSF Home Directory: /home/mobsf/.MobSF
[INFO] Downloading static analyzer dependencies...
[INFO] Applying migrations...
Operations to perform:
Apply all migrations: StaticAnalyzer, admin, auth, contenttypes, sessions
Running migrations:
Applying StaticAnalyzer.0001_initial... OK
[INFO] MobSF version: 4.3.2
[INFO] REST API Key: a190b3306dcd961cd7ecc6514369b22f50dddc858c68c4e4b0d620b442832ef4
Django version 4.2, using settings 'MobSF.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
Uploading a file with curl:
$ curl -F 'file=@/home/kali/apks/goatdroid.apk' http://127.0.0.1:8000/api/v1/upload \
-H "Authorization:a190b3306dcd961cd7ecc6514369b22f50dddc858c68c4e4b0d620b442832ef4"
{"file_name": "goatdroid.apk", "hash": "82ab8b2193b3cfb1c737e3a786be363a", "scan_type": "apk"}
Practical Examples with Output
Example 1 — Upload an APK for analysis:
$ curl -F 'file=@insecurebankv2.apk' http://127.0.0.1:8000/api/v1/upload \
-H "Authorization:$MOBSF_API_KEY"
{"file_name": "insecurebankv2.apk", "hash": "3a1f9e2b8c4d6f0a1b2c3d4e5f60718293", "scan_type": "apk"}
Example 2 — Trigger the static scan using the returned hash:
$ curl -X POST --url http://127.0.0.1:8000/api/v1/scan \
--data "hash=3a1f9e2b8c4d6f0a1b2c3d4e5f60718293" \
-H "Authorization:$MOBSF_API_KEY"
{"analyzer": "static_analyzer", "status": "success", "hash": "3a1f9e2b8c4d6f0a1b2c3d4e5f60718293"}
Example 3 — Check scan logs while analysis runs:
$ curl -X POST --url http://127.0.0.1:8000/api/v1/scan_logs \
--data "hash=3a1f9e2b8c4d6f0a1b2c3d4e5f60718293" \
-H "Authorization:$MOBSF_API_KEY"
{"logs": [
{"timestamp": "2026-07-19 10:12:01", "status": "Generating Hashes", "exception": null},
{"timestamp": "2026-07-19 10:12:02", "status": "Extracting APK", "exception": null},
{"timestamp": "2026-07-19 10:12:04", "status": "Parsing AndroidManifest.xml", "exception": null},
{"timestamp": "2026-07-19 10:12:09", "status": "Fetching Permissions", "exception": null},
{"timestamp": "2026-07-19 10:12:22", "status": "Performing Static Analysis of Source Code", "exception": null}
]}
Example 4 — Retrieve a simplified scorecard:
$ curl -X POST --url http://127.0.0.1:8000/api/v1/scorecard \
--data "hash=3a1f9e2b8c4d6f0a1b2c3d4e5f60718293" \
-H "Authorization:$MOBSF_API_KEY"
{
"version": "v1",
"title": "Mobile Security Framework (MobSF)",
"file_name": "insecurebankv2.apk",
"app_name": "InsecureBankv2",
"app_type": "apk",
"security_score": 32,
"high": 8,
"warning": 12,
"info": 6,
"secure": 3,
"hotspot": 2
}
Example 5 — Download the full JSON report:
$ curl -X POST --url http://127.0.0.1:8000/api/v1/report_json \
--data "hash=3a1f9e2b8c4d6f0a1b2c3d4e5f60718293" \
-H "Authorization:$MOBSF_API_KEY" -o insecurebankv2_report.json
$ ls -lh insecurebankv2_report.json
-rw-r--r-- 1 kali kali 512K Jul 19 10:15 insecurebankv2_report.json
Example 6 — Download the report as PDF:
$ curl -X POST --url http://127.0.0.1:8000/api/v1/download_pdf \
--data "hash=3a1f9e2b8c4d6f0a1b2c3d4e5f60718293&scan_type=apk" \
-H "Authorization:$MOBSF_API_KEY" -o insecurebankv2_report.pdf
$ file insecurebankv2_report.pdf
insecurebankv2_report.pdf: PDF document, version 1.4
Example 7 — List recent scans:
$ curl -X GET --url http://127.0.0.1:8000/api/v1/recent_scans \
-H "Authorization:$MOBSF_API_KEY"
{"content": [
{"MD5": "3a1f9e2b8c4d6f0a1b2c3d4e5f60718293", "APP_NAME": "InsecureBankv2", "PACKAGE_NAME": "com.android.insecurebankv2", "VERSION_NAME": "1.0", "FILE_NAME": "insecurebankv2.apk", "SCAN_TYPE": "apk", "TIMESTAMP": "2026-07-19 10:12:01"}
], "count": 1}
Example 8 — Search for a specific scan:
$ curl -X GET --url "http://127.0.0.1:8000/api/v1/search?query=insecurebankv2" \
-H "Authorization:$MOBSF_API_KEY"
{"3a1f9e2b8c4d6f0a1b2c3d4e5f60718293": {"MD5": "3a1f9e2b8c4d6f0a1b2c3d4e5f60718293", "APP_NAME": "InsecureBankv2", "PACKAGE_NAME": "com.android.insecurebankv2"}}
Example 9 — Trigger dynamic analysis on a connected Android device/emulator:
$ curl -X POST --url http://127.0.0.1:8000/api/v1/android/dynamic_analyzer \
--data "hash=3a1f9e2b8c4d6f0a1b2c3d4e5f60718293" \
-H "Authorization:$MOBSF_API_KEY"
{"status": "ok", "message": "Dynamic Analysis started successfully"}
Example 10 — Delete a scan and free storage:
$ curl -X POST --url http://127.0.0.1:8000/api/v1/delete_scan \
--data "hash=3a1f9e2b8c4d6f0a1b2c3d4e5f60718293" \
-H "Authorization:$MOBSF_API_KEY"
{"deleted": "yes"}
Example 11 — Compare two scans (regression testing between app versions):
$ curl -X GET --url "http://127.0.0.1:8000/api/v1/compare?hash1=3a1f9e2b&hash2=7c2e8f11" \
-H "Authorization:$MOBSF_API_KEY"
{"compare": {"added_permissions": ["android.permission.CAMERA"], "removed_permissions": [], "score_diff": -5}}
Example 12 — Using the mobsf-cli community wrapper for full CI automation:
$ mobsf-cli ci insecurebankv2.apk -p ./reports -c 5.5 -u 60 -t 5
Uploading insecurebankv2.apk...
Scanning...
Validating scan scores...
Error: Security score [32] is too low. Minimum required: [60].
Common Use Cases
- Rapid triage of unknown APKs – Quickly upload a suspicious or unfamiliar app and get an automated security scorecard before doing manual deep-dive analysis.
- CI/CD security gating – Wire the REST API into a build pipeline (Jenkins, GitLab CI, GitHub Actions) so every app build is automatically scanned and the build fails if the CVSS/security score drops below a threshold.
- Malware analysis – Analyze potentially malicious APKs in an isolated Docker container to identify permissions abuse, embedded trackers, and suspicious API usage without manually reverse engineering the sample.
- Regression testing across releases – Use the compare endpoint to see what changed (new permissions, new findings) between two versions of the same application.
- Dynamic instrumentation without manual Frida scripting – MobSF’s built-in dynamic analyzer automatically hooks common sensitive APIs (crypto, IPC, file system) using Frida, giving a tester a head start before writing custom hooks.
Automation with Bash
The following script automates the full MobSF workflow: upload, scan, poll until complete, and download both JSON and PDF reports.
#!/bin/bash
# mobsf_automate.sh - Automated MobSF scan workflow
MOBSF_URL="http://127.0.0.1:8000"
API_KEY="a190b3306dcd961cd7ecc6514369b22f50dddc858c68c4e4b0d620b442832ef4"
APK_FILE="$1"
if [ -z "$APK_FILE" ]; then
echo "Usage: $0 <path_to_apk>"
exit 1
fi
echo "[*] Uploading $APK_FILE..."
UPLOAD_RESPONSE=$(curl -s -F "file=@${APK_FILE}" "${MOBSF_URL}/api/v1/upload" \
-H "Authorization:${API_KEY}")
HASH=$(echo "$UPLOAD_RESPONSE" | grep -oP '"hash":\s*"\K[^"]+')
if [ -z "$HASH" ]; then
echo "[-] Upload failed: $UPLOAD_RESPONSE"
exit 1
fi
echo "[+] Uploaded. Hash: $HASH"
echo "[*] Starting scan..."
curl -s -X POST --url "${MOBSF_URL}/api/v1/scan" \
--data "hash=${HASH}" \
-H "Authorization:${API_KEY}" > /dev/null
echo "[+] Scan complete."
echo "[*] Downloading JSON report..."
curl -s -X POST --url "${MOBSF_URL}/api/v1/report_json" \
--data "hash=${HASH}" -H "Authorization:${API_KEY}" \
-o "${HASH}_report.json"
echo "[*] Downloading PDF report..."
curl -s -X POST --url "${MOBSF_URL}/api/v1/download_pdf" \
--data "hash=${HASH}&scan_type=apk" \
-H "Authorization:${API_KEY}" -o "${HASH}_report.pdf"
echo "[+] Done. Reports saved as ${HASH}_report.json and ${HASH}_report.pdf"
Sample run:
$ chmod +x mobsf_automate.sh
$ ./mobsf_automate.sh insecurebankv2.apk
[*] Uploading insecurebankv2.apk...
[+] Uploaded. Hash: 3a1f9e2b8c4d6f0a1b2c3d4e5f60718293
[*] Starting scan...
[+] Scan complete.
[*] Downloading JSON report...
[*] Downloading PDF report...
[+] Done. Reports saved as 3a1f9e2b8c4d6f0a1b2c3d4e5f60718293_report.json and 3a1f9e2b8c4d6f0a1b2c3d4e5f60718293_report.pdf
Tips and Best Practices
- Always run MobSF inside Docker for isolation, especially when analyzing potentially malicious samples — this prevents any exploit or malicious payload in the APK from touching your host system.
- Store the API key as an environment variable (
export MOBSF_API_KEY=...) rather than hardcoding it into scripts that might be committed to version control. - Use
X-Mobsf-Api-Keyheader as an alternative toAuthorizationif your proxy or firewall strips custom headers with generic names. - For dynamic analysis, always use a rooted emulator or a dedicated test device — never a personal or production device, since MobSF’s dynamic analyzer disables several security controls to enable instrumentation.
- Periodically clean up old scans using
/api/v1/delete_scan— analysis artifacts for large numbers of APKs can consume significant disk space in~/.MobSF. - Enable VirusTotal integration (via API key in the MobSF settings) for automated reputation checks against known malware hashes.
- When comparing scan results across app versions, keep the naming convention of your hash variables consistent in automation scripts to avoid confusing
hash1/hash2compare calls.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
401 Unauthorized on API calls | Wrong or missing API key | Copy the correct key from <MobSF_URL>/api_docs or the server startup logs |
Web UI unreachable at 127.0.0.1:8000 | Container/service not bound correctly | Re-run with -p 8000:8000 (Docker) or check ./run.sh 0.0.0.0:8000 for LAN access |
wkhtmltopdf errors when generating PDF reports | Missing or wrong-architecture binary | Install wkhtmltopdf manually and ensure it matches your OS architecture |
| Static analysis stuck at “Extracting APK” | Corrupted or non-standard APK (e.g., split APKs) | Use bundletool to merge split APKs/XAPKs into a single APK before upload |
| Dynamic analyzer fails to connect to device | ADB not detecting the emulator/device | Run adb devices to confirm connectivity before triggering /api/v1/android/dynamic_analyzer |
pip install -r requirements.txt fails during manual install | Missing system build dependencies | Install all packages listed in the manual installation step, especially libxml2-dev, libxslt1-dev, and libssl-dev |
| Migrations not applied / database errors | First run pending migrations | Run python manage.py migrate manually inside the activated virtual environment |
References
- MobSF Official GitHub Repository:
https://github.com/MobSF/Mobile-Security-Framework-MobSF - MobSF Official Documentation:
https://mobsf.github.io/docs/ - MobSF REST API Docs (from a running instance):
http://127.0.0.1:8000/api_docs - OWASP Mobile Application Security Testing Guide (MASTG):
https://mas.owasp.org/MASTG/ - MobSF Docker Hub Image:
https://hub.docker.com/r/opensecurity/mobile-security-framework-mobsf