feat: detect Koin DI and HMAC request-signing schemes
Two gaps in the previous coverage:
1. Koin was not mentioned anywhere — Hilt/Dagger got a full section in
call-flow-analysis.md but Koin (the dominant DI in KMP and a large
share of Kotlin-only Android apps) had zero patterns. Add a Koin
subsection with the runtime-DSL patterns (module {}, single<>,
factory<>, viewModel<>, by inject, by viewModel) plus the practical
trick for resolving an interface to its impl after R8 obfuscation:
intersect "files that import org.koin.core.module" with "files that
reference the interface name".
2. The --auth mode caught Bearer / API-key / OAuth header patterns but
missed HMAC and other request-signing schemes. A hardcoded HMAC
secret embedded in an APK is a security finding worth surfacing —
the same kind of authority the user gets is the same authority a
decompiler grants to anyone. Add patterns for:
* JCA primitives: HmacSHA{1,256,512}, Mac.getInstance(...),
SecretKeySpec(...), Signature.getInstance(...)
* Header conventions: X-Signature, X-Hmac, X-Amz-Signature,
X-Client-Authorization, AWS4-HMAC, signRequest(), signaturev2/3
* Likely secret-bearing identifiers: app_secret, client_secret,
signing_key, hmac_secret, consumer_secret, private_key
* Ktor BearerTokens / loadTokens / refreshTokens DSL
These survive R8 because the JCA and Ktor APIs are public and not
shrunk. On a real-world app with a homegrown HMAC scheme they pinpoint
the signing class and its hardcoded key directly.
This commit is contained in:
parent
2e6fc63453
commit
ec2b14c171
|
|
@ -84,9 +84,9 @@ Look for:
|
|||
- Firebase/analytics initialization
|
||||
- Base URL configuration
|
||||
|
||||
## 5. Dependency Injection (Dagger / Hilt)
|
||||
## 5. Dependency Injection
|
||||
|
||||
Modern Android apps use DI. Trace bindings to find implementations:
|
||||
### Dagger / Hilt
|
||||
|
||||
```bash
|
||||
# Hilt modules
|
||||
|
|
@ -102,10 +102,43 @@ grep -rn '@Component\|@Subcomponent' sources/
|
|||
grep -rn '@Inject' sources/
|
||||
```
|
||||
|
||||
To trace a call flow through DI:
|
||||
1. Find where an interface is used (e.g., `ApiService` injected into a repository)
|
||||
2. Find the `@Provides` or `@Binds` method that creates the implementation
|
||||
3. Follow the implementation to the actual HTTP call
|
||||
### Koin
|
||||
|
||||
Koin is the dominant DI framework in Kotlin Multiplatform and a large
|
||||
share of Kotlin-only Android apps. It uses a runtime DSL rather than
|
||||
compile-time generated factories, so the search patterns are different:
|
||||
|
||||
```bash
|
||||
# Confirm Koin is actually wired up
|
||||
grep -rn 'org\.koin\.' sources/
|
||||
|
||||
# DI module declarations
|
||||
grep -rn 'fun [A-Za-z]\+Module\|module\s*{\|module(' sources/
|
||||
|
||||
# Bindings inside a module DSL
|
||||
grep -rn 'single\s*[<{(]\|factory\s*[<{(]\|viewModel\s*[<{(]\|scoped\s*[<{(]\|singleOf\|factoryOf' sources/
|
||||
|
||||
# Resolution call-sites (where a binding is consumed)
|
||||
grep -rn '\bget\s*<\|\binject\s*<\|by\s\+inject\b\|by\s\+viewModel\b\|getKoin' sources/
|
||||
```
|
||||
|
||||
After R8, every binding lambda becomes an anonymous
|
||||
`Function2<Scope, ParametersHolder, T>` impl. To find the binding for an
|
||||
interface `Foo`, look for files that contain both a Koin import / module
|
||||
DSL marker and a reference to `Foo`:
|
||||
|
||||
```bash
|
||||
grep -rln 'org\.koin\.core\.module' sources/ | xargs grep -l 'Foo'
|
||||
```
|
||||
|
||||
### Trace through DI
|
||||
|
||||
1. Find where an interface is used (e.g. `ApiService` injected into a
|
||||
repository).
|
||||
2. Find the `@Provides` / `@Binds` method (Hilt) **or** the
|
||||
`single { ... }` / `factory { ... }` block (Koin) that creates the
|
||||
implementation.
|
||||
3. Follow the implementation to the actual HTTP call.
|
||||
|
||||
## 6. Find Constants and Configuration
|
||||
|
||||
|
|
|
|||
|
|
@ -226,9 +226,27 @@ fi
|
|||
# --- Auth patterns ---
|
||||
if [[ "$SEARCH_ALL" == true || "$SEARCH_AUTH" == true ]]; then
|
||||
section "Authentication & API Keys"
|
||||
run_grep -i '(api[_-]?key|auth[_-]?token|bearer|authorization|x-api-key|client[_-]?secret|access[_-]?token)'
|
||||
run_grep -i '(api[_-]?key|auth[_-]?token|bearer|authorization|x-api-key|client[_-]?secret|access[_-]?token|refresh[_-]?token)'
|
||||
|
||||
# Request-signing schemes: a hardcoded HMAC / RSA secret in an APK is a
|
||||
# security finding worth surfacing prominently. These patterns catch the
|
||||
# common shapes of homegrown / SDK-issued request signers.
|
||||
section "Request Signing (HMAC / signature schemes)"
|
||||
run_grep '(HmacSHA(1|256|512)|Mac\.getInstance\("Hmac|SecretKeySpec\(|Signature\.getInstance\()'
|
||||
run_grep -i '(x-signature|x-client-authorization|x-amz-signature|x-hmac|aws4-hmac|signRequest|signatureFor|computeSignature|signaturev[0-9])'
|
||||
|
||||
# Hardcoded high-entropy strings adjacent to "secret"/"key" assignments
|
||||
# are the canonical leaked-credential pattern.
|
||||
section "Possible Hardcoded Secrets / Keys"
|
||||
run_grep -i '(app[_-]?secret|client[_-]?secret|signing[_-]?key|hmac[_-]?secret|consumer[_-]?secret|private[_-]?key)'
|
||||
|
||||
section "Base URLs and Constants"
|
||||
run_grep -i '(BASE_URL|API_URL|SERVER_URL|ENDPOINT|API_BASE|HOST_NAME)'
|
||||
|
||||
# Ktor BearerTokens / refresh DSL — common on Kotlin apps and lives on
|
||||
# Ktor's public API, so it survives R8 unchanged.
|
||||
section "Ktor Auth (Bearer + Refresh)"
|
||||
run_grep '(BearerTokens|loadTokens\s*\{|refreshTokens\s*\{|\bbearer\s*\{)'
|
||||
fi
|
||||
|
||||
echo
|
||||
|
|
|
|||
Loading…
Reference in New Issue