Skip to content
Early access

A report you could send.

A pentest-ready teardown of acme-bank-4.2.apk, rendered from a firm template: summary, scope, findings, one full writeup and the method.

Fictional example. The target (Acme), findings and IDs are invented to show the report format.

Book a demo

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.

4Findings
2High severity
2Confirmed
4Refuted by the Disprover

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

IDFindingSeverityVerdictEvidence
KLY-0142Hardcoded AWS key in assets/config.jsonHighConfirmedCode · call path · re-runnable check
KLY-0143Request signing (HMAC-SHA256) recoverable from libcrypto_wrap.soHighConfirmedLifted native code · Burp extension
KLY-0147Certificate pinning bypassable via a debug build flagMediumLikelySmali + dynamic check on emulator
KLY-0151Exported activity allows a deep link to skip authLowUnverifiedStatic 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

Extracted at unpack
// 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

  1. MainActivity.onCreate()
  2. ReceiptSync.start()
  3. S3Uploader.load()
  4. assets/config.json

Reproduction

Run against the same artifact, the check extracts the key and calls sts:GetCallerIdentity with it.

Re-runnable check
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-uploader

Impact

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. 1

    Scope frozen

    The binary hash is recorded and the target list agreed before any agent runs.

  2. 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. 3

    Evidence collected

    Each claim is bound to decompiled code, a full call path and a command that reproduces it.

  4. 4

    Disprover pass

    A separate agent attempts to refute every claim: dead code, unreachable paths, alternate explanations. Refuted claims are dropped and logged.

  5. 5

    Dynamic confirmation

    Where a device or emulator can run the app, behaviour is observed rather than inferred.

  6. 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 →