How to Find Sensitive Information Hardcoded in an Android Application

Use a decompile-then-grep pipeline to extract readable Java/Kotlin source code from an APK and scan for patterns matching API keys, tokens, and hardcoded URLs.

Finding sensitive information hardcoded in an Android application requires reversing the compiled DEX bytecode back into human-readable source code and then systematically scanning for literals that expose secrets. The android-reverse-engineering-skill repository by SimoneAvogadro automates this workflow through a modular toolchain that decompiles APKs with jadx or vineflower and then greps the resulting tree for HTTP client signatures, authentication tokens, and hardcoded endpoints.

Decompile the APK to Expose Source Code

Android applications ship as APKs containing Dalvik Executable (DEX) bytecode, which obscures string literals. To find hardcoded sensitive information, you must first recover the original Java or Kotlin source representation.

Using JADX for Fast Decompilation

The decompile.sh script in plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh orchestrates the conversion. By default, it uses jadx to recursively decompile classes.dex into a structured source tree under output/sources/.

bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh path/to/target.apk

This produces readable .java and .kt files where constant fields, annotations, and string literals are restored to their original textual form, making them searchable with standard text tools.

Alternative Engines for Obfuscated Binaries

When the APK has been processed by ProGuard or R8, the default output may contain obfuscated class names. The skill supports Fernflower and Vineflower as alternative engines, which often yield higher-quality decompilations for heavily shrunken bytecode. You can configure the engine via environment variables or flags in the decompile script.

Scan Decompiled Sources for Hardcoded Secrets

Once the source tree is available, the find-api-calls.sh script—located at plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh—implements a pattern-based grep strategy to surface sensitive literals.

Pattern-Based Grep Strategies

The script references regex patterns defined in plugins/android-reverse-engineering/skills/android-reverse-engineering/references/api-extraction-patterns.md. These patterns target:

  • Hardcoded URLs: "https?://[^"]*"
  • Authentication tokens: api[_-]?key, auth[_-]?token, bearer, client[_-]?secret
  • HTTP method annotations: @GET, @POST, @Headers

Because the search runs against decompiled source rather than binary DEX, even secrets stored in private static final String constants or concatenated in StringBuilder chains are visible as discrete literals.

Identifying HTTP Client Signatures

Modern Android apps use specific networking libraries that leave distinct lexical signatures. The scanner groups findings by client type:

  • Retrofit: Detects baseUrl assignments and interface annotations like @GET("/users/{id}").
  • OkHttp: Identifies Request.Builder, HttpUrl.parse, and addInterceptor chains.
  • Volley: Matches StringRequest and JsonObjectRequest constructor calls.
  • HttpURLConnection: Finds openConnection() and setRequestProperty usage where headers might leak tokens.

By categorizing matches, the script helps you prioritize which findings are likely to be active API endpoints versus legacy debug code.

Locating Authentication Tokens and API Keys

To exclusively hunt for credentials, run the scanner with the --auth flag:

bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh output/sources/ --auth

Output appears in the format file:line:match, allowing you to jump directly to the source:


==== Authentication & API Keys ====

output/sources/com/example/app/network/AuthInterceptor.kt:7:api_key = "XyZ1234567890AbCdEfGhIjkLmNoPqRs"
output/sources/com/example/app/network/Constants.kt:3:CLIENT_SECRET = "mySuperSecret"

Each hit represents a hardcoded literal that may be a production secret, a staging key, or a deprecated credential. Contextual review of the surrounding code—whether the string is passed to an Authorization header or merely logged—determines the severity.

Practical Workflow Examples

Targeting Retrofit Annotations and Base URLs

For applications using Retrofit, combine the --retrofit and --urls flags to map the API surface and discover hardcoded endpoints:

bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh output/sources/ --retrofit --urls

This surfaces both the baseUrl defined in the Retrofit.Builder chain and the relative paths in @GET/@POST annotations, revealing the complete request URI even when split across multiple constants.

Manual Verification with Raw Grep

If the automated patterns miss a specific secret format used by your target, replicate the logic manually. The --urls flag is equivalent to:

grep -rnE '"https?://[^"]*"' output/sources/

You can extend this to custom patterns, such as internal UUIDs or proprietary token prefixes, by modifying the regex to match your threat model.

Handling Edge Cases in Android Reverse Engineering

String Concatenation and Dynamic Construction

When developers split URLs or keys across multiple constants—such as BASE_URL + "/api/v1"—the script captures both components as separate matches. The literal BASE_URL appears as a variable assignment, while "/api/v1" appears as a string fragment. To reconstruct the full value, grep for the definition of BASE_URL in the same file or package.

Encoded or Obfuscated Secrets

The scanner operates on plaintext decompiled source. Secrets encoded in Base64, hexadecimal, or encrypted at runtime will not match standard string patterns. For these cases:

  • Add regex patterns like [A-Fa-f0-9]{32,} for hex strings suspected to be API keys.
  • Search for Cipher, MessageDigest, or Base64 usage in the code to locate decryption routines that might reveal the final secret value.

Resource Files and XML Strings

The decompiler extracts resource IDs into the Java/Kotlin source, but the actual string values reside in res/values/strings.xml. The find-api-calls.sh script does not search XML resources. To audit these:

  • Inspect res/values/strings.xml in the decompiled output directory.
  • Alternatively, use aapt dump --values resources path/to/app.apk to view resource strings without full decompilation.

Summary

Frequently Asked Questions

What tools does the android-reverse-engineering skill use to decompile APKs?

The skill primarily uses jadx for fast, user-friendly decompilation, but also supports Fernflower and Vineflower for higher-quality output when dealing with ProGuard or R8-obfuscated binaries. These engines are orchestrated by the decompile.sh script located at plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh.

How does the script detect hardcoded API keys specifically?

The find-api-calls.sh script references regex patterns defined in plugins/android-reverse-engineering/skills/android-reverse-engineering/references/api-extraction-patterns.md. It searches for literals matching tokens like api[_-]?key, auth[_-]?token, bearer, and client[_-]?secret across all decompiled Java and Kotlin files, reporting matches in file:line:match format.

Can this method find secrets hidden in native libraries (.so files)?

No, the current toolchain focuses on decompiling DEX bytecode to Java/Kotlin source. Native libraries compiled to ARM/x86 machine code in .so files are not processed by jadx or the find-api-calls.sh script. To inspect these, you would need additional tools like Ghidra or IDA Pro to disassemble the native binaries.

Is it possible to detect secrets that are encrypted or obfuscated in the source?

Secrets that are encrypted, Base64-encoded, or constructed dynamically at runtime will not appear as plaintext literals in the decompiled source, so the standard grep patterns will miss them. However, you can identify these by searching for cryptographic API usage (Cipher, MessageDigest, Base64) in the codebase. If you suspect encoding, extend the search with custom regex patterns like [A-Fa-f0-9]{32,} for hex strings or manual decoding of suspicious variables.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →