# How to Find Sensitive Information Hardcoded in an Android Application

> Discover how to find hardcoded sensitive info in Android apps. Use a decompile-then-grep pipeline to scan APKs for API keys, tokens, and URLs.

- Repository: [Simone Avogadro/android-reverse-engineering-skill](https://github.com/SimoneAvogadro/android-reverse-engineering-skill)
- Tags: how-to-guide
- Published: 2026-04-17

---

**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`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/decompile.sh) script in [`plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/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
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`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/find-api-calls.sh) script—located at [`plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/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`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/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
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
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:

```bash
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`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/res/values/strings.xml). The [`find-api-calls.sh`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/find-api-calls.sh) script does not search XML resources. To audit these:

- Inspect [`res/values/strings.xml`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/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

- **Decompile first**: Convert DEX bytecode to Java/Kotlin using [`plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh) to expose string literals hidden in constant fields.
- **Scan for patterns**: Execute [`plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh) with flags like `--auth`, `--urls`, or `--retrofit` to surface hardcoded API keys, tokens, and endpoints.
- **Review context**: Validate findings by opening the reported file:line locations to determine if a literal is a production secret or a placeholder.
- **Handle edge cases**: Manually check for concatenated strings, hex-encoded secrets, and resource XML files that automated scripts might miss.

## 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`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/decompile.sh) script located at [`plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/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`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/find-api-calls.sh) script references regex patterns defined in [`plugins/android-reverse-engineering/skills/android-reverse-engineering/references/api-extraction-patterns.md`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/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`](https://github.com/SimoneAvogadro/android-reverse-engineering-skill/blob/main/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.