Self-hosted service
d78ui98/APKDeepLens avatar
d78ui98/APKDeepLens

APKDeepLens: static security scanning of an Android APK

Android security insights in full spectrum.

1,014 stars135 forksPythonMIT

At a glance

What is it?
APKDeepLens decompiles an APK with JADX and scans the resulting source for the OWASP Mobile Top 10, tagging every finding with a severity and an OWASP category, then exports JSON, HTML, PDF or plain text. It is a static tool: it reads the package and never runs the app, which is both its strength and its limit.
Who is it for?
Adopt APKDeepLens as one stage of an APK review, and use the JSON output as the input to a pipeline that gates releases on CRITICAL findings. Do not adopt it as a substitute for dynamic analysis, since it never executes the app, and do not treat its findings as a verdict on an application, because a static regex pass over decompiled source produces false positives.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 160 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A static scan of the package, not a run of the app

APKDeepLens is described as a Python-based static analysis tool for Android APK files. It decompiles APKs using JADX and then runs a deep multi-layer security scan covering the OWASP Mobile Top 10 from 2024. Every finding carries a severity level, one of CRITICAL, HIGH, MEDIUM, LOW or INFO, and an OWASP category, and results are exported in JSON, HTML, PDF or TXT.

The static nature of the analysis is the defining constraint. Nothing in the package is executed, no network traffic is generated and no device is needed, which makes the tool usable in a build pipeline against an artifact you already hold. It also means the tool sees what the code says rather than what the app does, and the difference between those two things is where both the false negatives and the false positives live.

The decompilation step is what makes the deeper checks possible at all. A raw APK is a zip of compiled artefacts, and searching it for a hardcoded key or a trust-all certificate verifier means searching binary output. Once JADX has produced Java, Kotlin and XML source, the checks become pattern matching over text, which is why the code scanner in this project counts its checks in the dozens.

Eleven categories, and where the check count sits

The detection table gives the shape of the scan. Manifest Security runs ten checks with a severity range from CRITICAL to MEDIUM and maps to M3 through M9. Cryptography has seven checks mapping to M1 and M10, and WebView Security has six mapping to M4, M5, M7 and M9 with a range up to HIGH. SSL and TLS has five checks against M5, and Dynamic Code Execution has four against M4 and M7 with a HIGH to MEDIUM range.

The rest are smaller. Insecure Data Storage covers six checks mapping to M4, M6 and M9. Logs and Privacy has three checks against M6, Intent Security has two against M4, and Zip Path Traversal has a single check at HIGH severity against M4. Hardcoded Secrets is the largest by far, listed as 16 or more checks with no severity range given, mapped to M1, and Insecure Communications is listed without a count.

That distribution is informative. A static analyser spends most of its effort on finding credentials and weak crypto, because those are visible in source, while the categories that need runtime observation, such as how data actually flows, are thin. DETECTION.md is the reference for the full check identifiers, the regular expression patterns and the evidence examples, and it also documents the JSON output schema.

Installing it on Linux, macOS or Windows

The requirements are Python 3.10 or newer and Java or OpenJDK, the second because JADX is a Java program. The Linux and macOS path is a virtual environment and a requirements install:

bash
git clone https://github.com/d78ui98/APKDeepLens.git
cd APKDeepLens
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python APKDeepLens.py --help

The Windows sequence is the same with a different activation line:

bash
python3 -m venv venv
.\venv\Scripts\activate
pip install -r requirements.txt
python APKDeepLens.py --help

The requirements file is short, holding only python-bidi at version 0.4.2 and xhtml2pdf at version 0.2.16, and both are pinned exactly. The bidi library is for bidirectional text handling, which matters when an app mixes scripts, and xhtml2pdf is what turns the HTML report into a PDF, so a PDF-only deployment still pulls the HTML templating in.

The last command in each sequence is the check that matters, because it confirms the entry point runs in the environment you just created rather than in a system Python.

The Docker image and its Python version mismatch

A Dockerfile is included, and the image is built and run in two commands:

bash
docker build -t apkdeeplens .
docker run --rm -v /path/to/apk/files:/apk apkdeeplens -apk /apk/file.apk

The base is python:3.8.12-slim with openjdk-11-jdk installed on top, so the container has both a Python and a JRE, and JAVA_HOME is set to the Java 11 path with the bin directory added to PATH. Dependencies are installed with pip and no cache directory, the source is copied in, and the default command is the help output of the entry point.

Here is a discrepancy worth catching before you deploy. The documentation asks for Python 3.10 or newer, while the container runs Python 3.8.12. If the code uses syntax or standard library features that arrived after 3.8, the container is the environment that breaks, and it breaks in a way that looks like a tool failure rather than a configuration problem. Either build on a newer base or test the image on a representative APK before you wire it into a pipeline.

The volume mount is the other detail. Mapping a directory of APKs into the container and pointing -apk at a file inside it is how you feed a batch of packages in without copying them into the image.

The command line and the report formats

Scanning one APK and choosing the output format are both single flags. The basic run produces a JSON report, and the format is set with -report:

bash
# Basic scan - outputs JSON report
python APKDeepLens.py -apk app.apk

# Generate HTML report
python APKDeepLens.py -apk app.apk -report html

# Specify output directory
python APKDeepLens.py -apk app.apk -report json -o /path/to/output/

Two more flags cover the situations that come up in a pipeline. The -source_code_path option skips decompilation when the source has already been extracted, which saves the slowest step when you are re-scanning after a rule change. The --ignore_virtualenv option exists for CI, where the check that the script is running inside a virtual environment would otherwise fail the job.

All reports are written to a reports/ subdirectory of the output path. The formats differ in who they are for. JSON is the default and is the one for machines: every finding includes an id, a severity, an owasp field, a description and evidence, which is what makes it usable as a pipeline gate. HTML and PDF are colour-coded severity tables for people, with CRITICAL in red, HIGH in orange and MEDIUM in amber. TXT is a severity-sorted human-readable list with file locations and descriptions.

Where APKDeepLens is the wrong tool

The first wrong-tool case is anything that needs runtime behaviour. A static scan cannot tell you whether an exported component is actually reachable, whether the certificate pinning can be bypassed at run time, or whether a permission is used in a dangerous way on a specific code path. If the question is what the app does on a device, the answer is not in the decompiled source.

The second is a code review that expects a low noise floor. The checks are regular expression patterns over decompiled code, and decompiled code is not the code the developer wrote. Obfuscation, string concatenation and reflection all hide things from a pattern match, and the project keeps a curated false-positive list in static_tools/known_false_positives.txt, which is an admission that the default output needs filtering. A team with a mature codebase should expect to tune that list before the signal is usable, and a team evaluating an unknown app should expect a manual triage step on every CRITICAL.

The third is a toolchain decision. The requirements are minimal, but the tool depends on JADX being present, and the decompilation step is the slowest part of the run. Scanning a large set of APKs on every build is a cost, and the JSON output exists precisely so you can scan once and gate on the result rather than re-run the tool on every commit.

MIT, conference appearances, and a May 2026 commit

The project is MIT licensed, with a LICENSE file at the repository root. It is not archived, and the last push was on 2026-05-16, and there are no GitHub releases, so the CHANGELOG.md at the root is the version history and the commit log is the release feed.

The README records where the tool has been shown, which is a reasonable proxy for how visible the project is: it was featured at Black Hat MEA 2023 under the name APKaleidoscope, at Black Hat ASIA 2024 and Black Hat MEA 2024 as APKDeepLens, and at GISEC Global Dubai 2024. The change of name between the 2023 session and the later ones suggests the project found its current form during that period.

The repository is small and readable, which is a plus for anyone who wants to check what a rule actually does. The entry point is APKDeepLens.py, report_gen.py handles the four output formats, report_template.html is the HTML template, and the static_tools/ directory holds the three scanners, the manifest parser, the sensitive-info extractor, the false-positive list and a shared utility class with the dangerous permissions constants. A testing_apps/ directory at the root holds sample packages to try the tool against, and issues and pull requests are the stated route for contributions.

Editorial conclusion

Adopt APKDeepLens as one stage of an APK review, and use the JSON output as the input to a pipeline that gates releases on CRITICAL findings. Do not adopt it as a substitute for dynamic analysis, since it never executes the app, and do not treat its findings as a verdict on an application, because a static regex pass over decompiled source produces false positives. Before you rely on it, read DETECTION.md for the check identifiers and the output schema, check the curated false-positive list in static_tools/known_false_positives.txt against your own codebase, and remember the Docker image runs Python 3.8.12 while the documentation asks for Python 3.10 or newer.

Frequently asked questions

How do I install APKDeepLens?

Clone the repository, create a virtual environment, activate it, run pip install -r requirements.txt and check the entry point with python APKDeepLens.py --help. The requirements are Python 3.10 or newer plus Java or OpenJDK, and a Dockerfile is also provided.

What does APKDeepLens detect in an APK?

It scans decompiled source across eleven categories, including manifest security, cryptography, WebView security, SSL and TLS misconfiguration, dynamic code execution, insecure data storage, sensitive data in logs, intent security, zip path traversal, hardcoded secrets and insecure communications. Each finding is tagged with a severity and an OWASP Mobile Top 10 category.

Which report format should I use for CI?

JSON, which is the default. Every finding includes an id, severity, owasp, description and evidence, and the README describes it as the format for pipeline integration. HTML and PDF are colour-coded tables for people, and TXT is a severity-sorted list with file locations.

Does APKDeepLens run the app it scans?

No. It is a static analysis tool. It decompiles the package with JADX and reads the resulting source, so it reports what the code contains rather than what the app does at run time.

How do I skip decompilation when the source is already extracted?

Pass the -source_code_path option with the directory holding the source. The other flag worth knowing in automation is --ignore_virtualenv, which exists so the job does not fail outside a local virtual environment.

Official sources

  1. d78ui98/APKDeepLens on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/d78ui98-apkdeeplens.svg)](https://hysenlabs.com/projects/d78ui98-apkdeeplens)

Was this useful?