KLEYDIN REPORT · DRAFT FOR REVIEW
Mobile application security assessment: Acme Bank for Android
- Target
- acme-bank-4.2.apk
- SHA-256
- 9f2c…a71d
- Platform
- Android · minSdk 24 · targetSdk 34
- Analysis
- an_8f21 · October 2026
- Template
- firm-template.docx
Executive summary
Four findings survived validation on Acme Bank 4.2 for Android: two High, one Medium and one Low. Two are confirmed, one is likely, and one is flagged for a human to take further. Four further candidate findings were refuted by the Disprover and are listed in the run log rather than here.
The two High findings share a root cause: secrets and security logic shipped inside the package on the assumption that the client is trusted. An AWS access key sits in assets/config.json and was live at test time, giving read and write access to a receipts bucket from any copy of the app. The request-signing routine in the bundled native library was recovered well enough to rebuild as a working Burp extension, so an attacker can sign arbitrary requests to the bank's API.
Neither finding requires a rooted device, a modified app or privileged access. Rotating the key and moving signing material behind an attested server-side exchange addresses both.
Scope
One Android release build, analysed from the compiled artifact alone. No source code, build system access or developer documentation was provided.
- In scope
- acme-bank-4.2.apk · all bundled DEX, native libraries and assets
- In scope
- API endpoints reachable from the app, enumerated statically and observed on an emulator
- Out of scope
- Server-side application logic and infrastructure
- Out of scope
- Third-party SDK back ends · physical device attacks
- Dynamic testing
- Pixel 6 emulator · Android 14 · test tenant only
Findings
| ID | Finding | Severity | Verdict | Evidence |
|---|---|---|---|---|
| KLY-0142 | Hardcoded AWS key in assets/config.json | High | Confirmed | Code · call path · re-runnable check |
| KLY-0143 | Request signing (HMAC-SHA256) recoverable from libcrypto_wrap.so | High | Confirmed | Lifted native code · Burp extension |
| KLY-0147 | Certificate pinning bypassable via a debug build flag | Medium | Likely | Smali + dynamic check on emulator |
| KLY-0151 | Exported activity allows a deep link to skip auth | Low | Unverified | Static only · needs a device |
Severity follows the firm's own scale; the verdict states how far Kleydin proved the claim. The two are independent: a Low finding can be Confirmed, and a High one Unverified.
KLY-0142: Hardcoded AWS key in assets/config.json
HighConfirmed
Description
The release package ships a long-lived AWS access key pair in assets/config.json. S3Uploader.load() reads the file at runtime and constructs static credentials for the acme-bank-receipts bucket. The file is plain JSON inside the APK: no obfuscation, no key derivation, no runtime exchange. Any copy of the app contains the same credentials, so extracting them requires only unzip.
Evidence
// assets/config.json: extracted at unpack { "region": "eu-west-1", "accessKeyId": "AKIA………7QF2", "secretAccessKey": "wJal………EKEY", "bucket": "acme-bank-receipts" } // com/acme/bank/core/S3Uploader.java (decompiled) private static AWSCredentials load() { JSONObject c = Assets.json("config.json"); return new BasicAWSCredentials(c.get("accessKeyId"), c.get("secretAccessKey")); }
Call path
- MainActivity.onCreate()
- ReceiptSync.start()
- S3Uploader.load()
- assets/config.json
Reproduction
Run against the same artifact, the check extracts the key and calls sts:GetCallerIdentity with it.
1 unzip acme-bank-4.2.apk assets/config.json
2 aws sts get-caller-identity (with the recovered key)
→ key present · sts:GetCallerIdentity 200 · arn:aws:iam::…:user/acme-mobile-uploaderImpact
The credentials were live at test time and resolved to an IAM user with read and write access to acme-bank-receipts. Receipts contain account numbers and transaction detail, so the exposure is a direct confidentiality breach for every customer whose receipts are stored there, and write access allows tampering with stored documents.
Because the key is identical in every installation, rotation is the only remediation that takes effect without a release; revoking it will break receipt upload for all users still on 4.2 and earlier.
Remediation
- Revoke the key pair immediately and audit CloudTrail for use from outside Acme infrastructure
- Remove the credentials from the repository history, not just the build
- Move uploads behind an authenticated API endpoint, or issue short-lived STS credentials scoped to one user's prefix after login
- Add a build-time secret scan that fails the pipeline on credential material in
assets/
Appendix A: Methodology
Every Kleydin analysis follows the same six stages, and each stage is recorded in an audit trail that can be replayed.
- 1
Scope frozen
The binary hash is recorded and the target list agreed before any agent runs.
- 2
Autonomous teardown
Platform agents unpack, decompile and lift the binary, then follow leads on their own: manifest, DEX, native libraries, assets and network layer.
- 3
Evidence collected
Each claim is bound to decompiled code, a full call path and a command that reproduces it.
- 4
Disprover pass
A separate agent attempts to refute every claim: dead code, unreachable paths, alternate explanations. Refuted claims are dropped and logged.
- 5
Dynamic confirmation
Where a device or emulator can run the app, behaviour is observed rather than inferred.
- 6
Human review
A reviewer reads every finding and its evidence before the report is released.
Detection and false-alarm rates for the method are published with the corpus and the scoring rules. See the benchmarks →