An integrated mobile security platform for Android applications — SAST + MobSF + emulator‑based dynamic analysis + DAST (Nuclei) + AI‑assisted reporting, all in a single pipeline.
AppRay takes an Android APK from one panel and runs it through static analysis, professional mobile scanning, a live emulator‑based dynamic session, and live‑target DAST verification, then consolidates everything into one unified, AI‑annotated report.
Developed as a graduation thesis project at Amasya University, Department of Computer Engineering. Academic title: “Integrated SAST, DAST and Dynamic Analysis Platform for Android Applications: AppRay”.
AppRay is an academic / educational security‑research tool. It is intended for defensive and authorized testing only.
You may use AppRay only on:
- applications, APIs and infrastructure that you own, or
- targets for which you have explicit, written authorization to perform security testing.
Do not use AppRay — or any detection rule, exploit template, or integration you build on top of it — to scan, attack, fingerprint, or extract data from applications, services, or networks that you do not own or are not authorized to assess. In particular:
- 🚫 No malicious use, and no malicious development. Do not extend this project to weaponize it against third parties, to evade detection for offensive purposes, or to harvest credentials/data from systems you don’t control.
- 🚫 The bundled custom Nuclei templates are deliberately offensive (they dump user tables, perform UNION‑based SQLi, and prove IDOR). By design they are gated to local / staging targets only (see Writing Custom Detection Rules). Do not remove that gating to point them at external hosts.
- ⚖️ Unauthorized scanning, access, or exploitation of computer systems is illegal in most jurisdictions. You are solely responsible for ensuring your use complies with all applicable laws and contracts.
- 🤝 If you discover a real vulnerability in third‑party software while learning with this tool, practice responsible disclosure.
- 🧪 The included ShopNex / VulnShop target is an intentionally vulnerable app meant to be run locally, in an isolated environment, purely for demonstration and learning. Never deploy it on a public network.
This software is provided “as is”, without warranty of any kind (see LICENSE.md). The authors accept no liability for any misuse or damage caused by this tool.
By using or forking this repository, you agree to use it lawfully and ethically.
- Key Features
- Screenshots
- Architecture
- Tech Stack
- Quick Start
- How the Pipeline Works
- ✍️ Writing Custom Detection Rules
- Test Application — ShopNex / VulnShop
- AI Layer
- Project Layout
- License & Academic Note
- Multi‑source APK intake — upload a file, download from a URL (with mirror fallback), build straight from a GitHub repository, or fetch by package name (mirror → Play Store fallback). Each source is validated with fail‑fast checks (ZIP magic bytes, package‑name regex).
- SAST — JADX decompilation + 16 regex categories (Firebase/cloud, secrets, dangerous permissions, hardcoded credentials, log leakage, insecure WebView, exported components, SSL bypass, deep links, Retrofit endpoints, base URLs, weak crypto, backup/debuggable flags, …), live Firebase/bucket testing, and AI‑summarized critical findings.
- MITRE CWE integration — findings are mapped to the CWE Comprehensive Dictionary (~969 weaknesses); the UI shows an expandable “MITRE CWE Detail” panel with description, likelihood and mitigations, translated to Turkish on demand.
- Dynamic analysis — APK installed on a Dockerized Android emulator, mitmproxy CA injected, app launched. A manual‑control mode lets the analyst log in / complete OTP & permissions before automated discovery starts, followed by a bounded Monkey fuzzing pass.
- Live traffic capture — a custom mitmproxy addon captures
Authorizationtokens andSet‑Cookiesessions, filters out system noise, and feeds real application endpoints into the DAST queue. - DAST — captured live targets are scanned with Nuclei, including custom mobile‑API templates; results are summarized by an LLM as a Turkish pentest report.
- Unified report — SAST and DAST findings are presented together with source badges, severity, technical evidence, and CWE panels.
- Real‑time UI — a vanilla‑JS Single Page App (clean History‑API URLs) with SignalR live scan progress and notifications, plus dark/light themes.
ℹ️ The product UI is in Turkish (the project’s academic language). The screenshots below are captioned in English.
Pick the APK source (Upload · URL · GitHub Repo · Package Name), name the app, and choose the environment (Production = manual‑login dynamic flow, Test = aggressive fuzzing). The right panel summarizes which modules will run.
The four intake channels. “GitHub Repo” clones and builds the project; “Package Name” tries public mirrors first, then the Play Store fallback.
All scans with their status (Completed · Completed with warnings · Failed) and per‑scan counts of vulnerabilities, SAST and DAST findings. Each card offers Detail and Restart.
The pipeline stages (Build → SAST → MobSF → DAST → Done) update in real time over SignalR. In manual mode the “Go to Emulator / I’ve Logged In, Continue” buttons gate the dynamic step.
A consolidated “RoboApp Report”: an executive brief, severity breakdown (High / Medium / Info), filter pills, and per‑finding cards with technical evidence, CWE / OWASP MASVS tags, source badge, and remediation advice.
Sidebar‑style settings: Play Store integration (for package‑name intake), appearance (dark/light), and platform placeholders.
The bundled demo target used to validate the pipeline end‑to‑end.
APK Intake → SAST → (parallel) MobSF + Dynamic Analysis → DAST → Unified Report
Frontend SPA (SignalR) Android Emulator (noVNC)
│ │
▼ ▼
AppRay.WebApi (8080) ──► RabbitMQ ──► AppRay.DastScanner ──► Nuclei ──► live target
│ orchestration ▲
├─► AppRay.SastScanner (JADX + regex + CWE KB + AI)
├─► MobSF (8000)
└─► mitmproxy addon ──► token / login webhooks ──┘
│
▼
PostgreSQL (5433) Ollama (Llama 3.1 + LLaVA, on host)
| Service | Port (host) | Role |
|---|---|---|
appray-webapi |
8080 | Orchestrator, SPA host, pipeline manager, SignalR hub |
appray-sastscanner |
— | JADX decompile + 16 regex categories + Firebase/bucket tests + AI summary |
appray-dastscanner |
— | RabbitMQ dast_targets consumer → Nuclei → AI pentest report |
appray-postgres |
5433 | PostgreSQL database (scans, findings, sessions) |
appray-rabbitmq |
5672 / 15672 | AMQP queue + management UI |
appray-mobsf |
8000 | MobSF mobile analysis |
appray-emulator |
6080 | Android 11 emulator (browser access via noVNC) |
appray-mitmproxy |
8887 / 8889 | Traffic capture + token/login webhooks |
appray-vampi |
5000 | Intentionally vulnerable REST API (Nuclei test target) |
| Ollama | 11434 | Llama 3.1 + LLaVA (runs on the host, outside Docker) |
.NET 8 (C#) · PostgreSQL · RabbitMQ · Docker Compose · Python (mitmproxy addon) · Vanilla JS SPA (History API) · SignalR · JADX · Nuclei · MobSF · Ollama (Llama 3.1 + LLaVA)
Requirements: Docker + Docker Compose, hardware virtualization (
/dev/kvm) for the emulator, and (optionally) Ollama on the host for the AI layer.
git clone https://github.com/fuatsimsek/appray.git
cd appray
# JADX is gitignored — download it and extract into ./jadx_tool/
# https://github.com/skylot/jadx/releases
# (optional) AI layer on the host
ollama pull llama3.1
ollama pull llava
docker compose up -d postgres rabbitmq mobsf android-emulator mitmproxy vampi
docker compose up -d webapi dastscannerThen open:
| Service | URL |
|---|---|
| Dashboard | http://localhost:8080 |
| Emulator (noVNC) | http://localhost:6080 |
| RabbitMQ UI | http://localhost:15672 (guest / guest) |
| MobSF | http://localhost:8000 |
| mitmweb | http://localhost:8889 (password: appray) |
wwwroot/is volume‑mounted, so HTML/CSS/JS changes apply without a rebuild (just hard‑refresh). C# changes require an image rebuild.
POST /api/scansrecords the scan and starts SAST (AppRay.SastScanner).- On SAST success, status becomes
sast_doneand MobSF + Dynamic analysis run in parallel (Task.Run). - Dynamic: install APK on the emulator, inject the mitmproxy CA, launch the app, hand control to the analyst (manual login/OTP), run bounded Monkey fuzzing, collect traffic + SharedPrefs + logcat.
- Captured & normalized URLs (third‑party noise stripped) are pushed to the
dast_targetsRabbitMQ queue with the captured auth header. AppRay.DastScannerconsumes targets, runs Nuclei, and (on hits) generates a Turkish AI pentest summary.- The pipeline waits for DAST completion before marking the scan
completed, so the unified report is always complete when shown.
One of AppRay’s goals is to make it easy to add your own detection logic. There are two extension points: SAST regex categories (static) and custom Nuclei templates (dynamic). Below is exactly how the bundled rules (e.g. the SQL‑injection check) were integrated.
Static detections live in a single dictionary in
AppRay.SastScanner/Analysis/VulnerabilityAnalyzer.cs → DeepScanAsync():
var searchPatterns = new Dictionary<string, Regex>
{
["🔥 Firebase & Cloud"] = new Regex(@"https?://[\w\.-]+\.(?:firebaseio\.com|s3\.amazonaws\.com|appspot\.com)", ...),
["🔑 Sensitive Keys"] = new Regex(@"(?:api_key|aws_secret|auth_token|client_secret|...)...", ...),
// … 16 categories shipped by default …
// 👉 YOUR NEW RULE — just add another entry:
["🧨 Hardcoded JWT"] = new Regex(
@"eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}",
RegexOptions.Compiled),
};That’s the minimum. The key ("emoji Name") becomes the finding category; every match in the decompiled sources is collected, grouped per category, and written to the DB.
To make the finding richer in the UI, also:
- Filter false positives — extend
LibraryNoiseRegexin the same file if your pattern matches framework/library URLs (XML namespaces, license URLs, etc.). Noise matches are dropped before they reach the DB. - Map to a CWE / OWASP reference — add a case for your category in
VulnerabilityKB.cs(GetInfo) so the report shows the CWE id, OWASP MASVS tag, description and remediation. CWE details/translations are then enriched automatically from the MITRE knowledge base.
Rebuild the scanner image so the new C# is picked up.
Dynamic detections are plain Nuclei YAML files in
nuclei-custom-templates/. The bundled ones target the mobile API of the test app:
| Template | Severity | What it proves |
|---|---|---|
mobile-api-users-exposure.yaml |
critical | /api/users returns all users + plaintext passwords with no auth |
mobile-api-sqli-union.yaml |
high | /api/products?search= is UNION‑SQLi → dumps the users table |
mobile-api-idor.yaml |
high | a low‑priv token reads another user’s profile (IDOR / BOLA) |
A minimal custom template looks like this (note {{RootURL}}):
id: my-custom-api-check
info:
name: My Custom Mobile API Check
author: you
severity: high
tags: mobile,api,custom
http:
- method: GET
path:
- "{{RootURL}}/api/secret-endpoint"
matchers-condition: and
matchers:
- type: status
status: [200]
- type: word
words: ["password", "token"]
condition: andRules that matter (learned the hard way):
- ✅ Use
{{RootURL}}, not{{BaseURL}}. The pipeline hands Nuclei the full captured URL (path included);{{BaseURL}}would re‑append the path and hit the wrong target. - 📦 Mounting —
docker-compose.ymlmounts the folder into the scanner:Templates are volume‑mounted, so you just restart the scanner (appray-dastscanner: volumes: - ./nuclei-custom-templates:/root/nuclei-templates/custom
docker compose restart dastscanner) — no rebuild, and don’t hand‑copy files into the container (they’re lost on restart). - 🔒 Safety gating (
isLocal) — custom templates only run against local / staging targets. InAppRay.WebApi/Program.csa target is considered local when its host matcheshost.docker.internal,localhost,127.*,10.0.2.2,172.*, or192.168.*. Only then doesAppRay.DastScanner/ExploitEngine.csadd-t custom/to the Nuclei command:This is intentional: your offensive templates never fire at arbitrary external hosts. Keep it that way.// ExploitEngine.cs — local targets get the aggressive set incl. custom/ templates = "-t network/ -t http/default-logins/ -t http/misconfiguration/ " + "-t http/vulnerabilities/ -t http/exposures/ -t custom/";
The pipeline is validated against ShopNex (package com.vulnshop), an intentionally vulnerable e‑commerce app (Android client + Flask/SQLite REST API) — see github.com/fuatsimsek/VulnShop. Planted flaws include: SQLi (login + search), IDOR (cart/orders/profile), weak JWT, plaintext passwords, hardcoded secrets, cleartext HTTP, insecure WebView + JavaScript bridge token leak, and MD5 usage — covering both the SAST and DAST sides.
⚠️ ShopNex is deliberately insecure. Run it only in an isolated local environment. Never expose it publicly.
| Model | Used for |
|---|---|
| Llama 3.1 | SAST/DAST summary reports, URL categorization, password‑realism classification, CWE Turkish translation |
| LLaVA | Interpreting emulator screens (form/button detection) during the manual dynamic session |
Principle: AI is an assistive commentary layer, not a decision‑maker. The real detection is done by regex rules, the rule engine, and Nuclei. Ollama runs on the host at http://localhost:11434.
AppRay/
├── docker-compose.yml
├── AppRay.WebApi/ # orchestrator, SPA host, SignalR, pipeline
├── AppRay.SastScanner/ # JADX + regex categories + CWE KB + AI
├── AppRay.DastScanner/ # RabbitMQ consumer + Nuclei + AI report
├── mitmproxy_addon/ # token/login webhooks
├── nuclei-custom-templates/# custom mobile‑API DAST templates
├── android-emulator/ # emulator Dockerfile
├── gplaycli/ # Play Store APK fetcher
└── docs/screenshots/ # README images
Released under the MIT License — see LICENSE.md. This is a university graduation project intended for education and authorized security research; please honor the Responsible Use terms above.
Acknowledgements: built on the excellent open‑source work of JADX, Nuclei, MobSF, mitmproxy, RabbitMQ, Ollama, and the OWASP MASTG.






