Friday, November 6, 2026
HomeDeveloper Corner, APIs & Reverse Engineering7 Tools to Perform Static & Dynamic Application Security Audits

7 Tools to Perform Static & Dynamic Application Security Audits

A security audit asks a simple question in a systematic way. It asks what an app does with data and where that data can leak. Static analysis answers part of that question by reading code without running it. Dynamic analysis answers another part by running the app and watching its behaviour. A good audit uses both methods because each method misses flaws that the other method finds.

Static tools can scan a large codebase fast. They flag hard coded secrets and weak encryption and risky permissions. They also produce false positives that need human review. Dynamic tools can prove that a flaw is real by showing data leaving the device. They need a running app and a test plan that covers real user flows. Together they give a fuller picture than either method alone.

This guide covers seven tool types for auditing your own Android apps. It does not cover tools for attacking apps that belong to other people. Use the tools here on code that you own or on apps that you have clear permission to test. A structured audit protects users and it protects your team from surprises after release.

Static tools that read code without running it

A code scanner reads source code or bytecode and looks for known risky patterns. It can flag a weak hash function or a clear text network call or a hard coded key. It can also trace data from a source such as location to a sink such as a network request. That trace helps a reviewer judge whether a flow is safe or whether it leaks sensitive data.

A dependency scanner checks libraries against known vulnerability lists. An app may be secure in its own code while a library carries a known flaw. Update the library or replace it when a scanner reports a serious issue. Record the decision for each flagged library so the next audit does not repeat the same research.

A manifest and configuration checker reviews permissions and exported components and network settings. It flags a component that is exported without a reason. It flags clear text traffic that should use encryption. Those checks are fast and they catch configuration errors that code review often misses.

Dynamic tools that watch a running app

A proxy tool sits between the app and the network and records requests. It shows which domains receive data and what that data contains. Run the app through its main flows while the proxy records traffic. Look for personal data in plain text and for tokens sent to unexpected domains. That evidence is stronger than a guess from code alone.

A runtime instrumentation tool can hook methods while the app runs. It shows when a sensitive API is called and what value it returns. Use it on your own test app to confirm that a security control actually runs. A control that exists in code but never runs during a real flow gives no protection in practice.

A device monitor records file writes and log output and permission use during a test. It can reveal a token written to a log file or a sensitive file left on shared storage. Those findings are easy to fix once you see them. A monitor turns a vague worry about leakage into a concrete file path and a concrete fix.

Choosing tools for a small team

A small team should start with one static scanner and one proxy tool. Those two tools cover a large share of common flaws. Add a dependency scanner next because library flaws are common and easy to check. Add runtime tools when the team has a repeatable test plan for the app main flows. A tool without a test plan produces noise rather than insight.

Cost and setup time matter as much as feature lists. An open source scanner that the team actually runs beats a complex commercial tool that no one opens. Test each tool on a small project first. Measure setup time and false positive rate and report clarity. Choose tools that the team will use for every release rather than tools that impress in a demo.

Integrate the chosen tools into the build or the release checklist. A scanner that runs in continuous integration catches a flaw on the day that it appears. A manual audit that runs once a year catches the same flaw months later. Automation does not replace human review but it makes human review focus on the findings that matter most.

Running an audit from start to finish

Start an audit with scope and a test account. List the features that handle sensitive data such as login and payment and messaging. Create a test account with fake data that looks real enough to exercise those features. Never use a real user account or real personal data for a dynamic audit. Fake data protects users while still exercising the code paths.

Run static tools first and triage the results. Sort findings by severity and by confidence. Fix high severity and high confidence findings first. Review medium findings with a second person when possible. Record false positives with a reason so the next run does not waste time on the same finding.

Run dynamic tests next and cover each sensitive flow end to end. Record network traffic and file writes and log output for each flow. Compare dynamic evidence with static findings. A static flag that dynamic testing confirms becomes a priority fix. A static flag that dynamic testing cannot reproduce still deserves a code review but with lower urgency.

  • Define scope and create a test account with fake data.
  • Run static tools and triage findings by severity.
  • Run dynamic tests for each sensitive user flow.
  • Compare static and dynamic evidence before fixing.

Code you can adapt

# Example audit checklist in plain text form
# Static: scan code and dependencies and manifest
# Dynamic: proxy traffic for login and payment flows
# Files: check logs and shared storage after each flow
# Result: record severity and evidence for each finding
audit_scope = ["login", "payment", "profile", "messaging"]
for flow in audit_scope:
    print("Audit flow: " + flow)

The snippet above is an original example written for this guide. It shows a simple audit scope list that keeps static and dynamic work focused on sensitive flows.

A scope list keeps an audit from drifting into every corner of an app. Sensitive flows deserve the deepest testing. Less sensitive flows still deserve a static scan but they do not need the same dynamic depth. That balance lets a small team finish an audit in a reasonable time.

Record evidence for each finding in a short note. Note the tool and the flow and the data that leaked or the code that caused the risk. A finding with evidence is easy to fix and easy to verify after the fix. A finding without evidence often gets debated and delayed.

How this topic connects to nearby work

One audit finding that appears often is described in the guide to APK obfuscation mistakes for developers.

Audit evidence becomes clearer when you understand the methods surveyed in the guide to APK modding techniques.

Storage findings from an audit often lead to the encryption approach in the guide to encrypted local storage using Android Keystore.

Putting it into practice

Report writing turns audit findings into fixes that a team can act on. A good report lists each finding with severity and evidence and a suggested fix. It also lists the flows that were tested and the tools that were used. A report without evidence becomes a debate about whether the finding is real. A report with a concrete traffic capture or a code reference becomes a task that a developer can start immediately.

Retesting after a fix closes the audit loop. Run the same static scan and the same dynamic flow that found the original issue. Confirm that the finding no longer appears and that no new finding appeared from the fix. Record the retest result beside the original finding. An audit without retesting leaves the team guessing whether a fix actually worked.

A final audit check should review the audit scope itself after the first full audit. Ask whether any sensitive flow was left out because it seemed too small to matter. A small flow that handles a token or a password reset link can matter as much as a large payment flow. Add any missed flow to the scope list for the next audit. A scope review after each audit keeps the next audit more complete than the last one. That improvement compounds over several audit cycles.

Common mistakes

A common mistake is to run only static tools and call the audit complete. Static tools miss runtime behaviour such as data sent after encryption or data written by a library at runtime. Dynamic testing catches those cases. Use both methods for any app that handles sensitive data.

Another mistake is to audit only the main app code and ignore libraries. Libraries can leak data and they can introduce vulnerabilities. Include libraries in the dependency scan and in dynamic traffic review. A library that sends analytics data deserves the same scrutiny as your own code.

A third mistake is to treat an audit as a one time event. Code changes every week and new vulnerabilities appear often. Repeat the audit for major releases and after adding a new library or a new sensitive feature. A regular audit keeps security close to the pace of development.

Frequently asked questions

Which method finds more flaws static or dynamic analysis?

Neither method wins in all cases. Static analysis finds code flaws fast across a large codebase. Dynamic analysis proves real behaviour during actual use. A strong audit uses both methods and compares their results for sensitive flows.

How often should a small team audit an Android app?

Audit for every major release and after a new library or a new sensitive feature. Run automated static scans in continuous integration for every change. Reserve full dynamic testing for releases that touch login or payment or personal data.

What should I do with a false positive from a scanner?

Record it with a clear reason and a code reference. A recorded false positive saves time on the next run. Do not suppress a finding without a reason because a real flaw can hide behind a careless suppression.

Conclusion

Static and dynamic audits complement each other. Static tools scan widely and fast. Dynamic tools prove behaviour in a running app. A team that uses both methods and records evidence will find more real flaws and waste less time on noise. Scope the audit to sensitive flows and repeat it for major releases.

Your concrete next step is to pick one static scanner and one proxy tool today and run both on your own test app. Record the top three findings from each tool. That short exercise will show you which method finds the flaws that matter most for your app.

RELATED ARTICLES

Most Popular