Common Hardcoded Credentials in Document Scanning Apps: Causes and Fixes
Hardcoded credentials appear when developers embed secrets directly in source files instead of using a secure vault or configuration service. In document scanning apps this typically happens for three
1. Technical root causes of hardcoded credentials in document scanning apps
Hardcoded credentials appear when developers embed secrets directly in source files instead of using a secure vault or configuration service. In document scanning apps this typically happens for three technical reasons:
- Rapid prototyping – early‑stage code often uses a static username/password pair to get the scanner talking to a backend API. The convenience of “just works” outweighs the habit of externalizing secrets.
- Legacy integration – many scanning solutions were built to consume on‑premises document‑management systems that required hard‑coded service accounts. When the product migrated to cloud APIs, the original credentials were left untouched.
- Insufficient secret‑management practices – lack of a centralized secret store (e.g., HashiCorp Vault, AWS Secrets Manager) forces developers to store keys in
.propertiesfiles,config.xml, or even directly in the app’s assets folder.
The result is that the credential value travels with the binary, making it visible to anyone who can decompile the APK or inspect the web bundle.
---
2. Real‑world impact
When hardcoded credentials leak, the fallout is measurable and immediate:
- User complaints – scanning failures become a recurring theme in reviews (“The app crashes after login”, “It keeps asking for a password that never works”). Negative sentiment drives a drop in store rating.
- App‑store rating erosion – a 1‑star surge can shave 10‑15 % off download conversions, especially in categories where trust is paramount (e.g., legal‑document scanning).
- Revenue loss – lower conversion rates translate directly into fewer paid scans or subscription upgrades. For a SaaS‑backed scanner, a 5 % dip in paid‑user acquisition can mean thousands of dollars per month.
These symptoms are not abstract; they are reflected in analytics dashboards that show spikes in crash reports and support tickets after a compromised release.
---
3. Specific ways hardcoded credentials manifest in document scanning apps
| # | Manifestation | Typical Code Location | Example |
|---|---|---|---|
| 1 | Plain‑text API key in the Android strings.xml | res/values/strings.xml | |
| 2 | Hard‑coded Basic Auth header in Java/Kotlin | AuthHelper.kt | val credentials = "admin:password" then val header = "Basic " + Base64.encodeToString(credentials.toByteArray(), Base64.NO_WRAP) |
| 3 | Embedded credentials inside the iOS bundle’s Info.plist | Info.plist | |
| 4 | Credential file shipped with the installer | assets/credentials.json | {"client_id":"client123","client_secret":"secret789"} |
| 5 | Hard‑coded service account in a Docker image | Dockerfile ENV SCAN_USER=scanadmin SCAN_PASS=scan123 | Image used for server‑side scanning endpoints. |
| 6 | Configuration stored in a public Git repository | config.py in repo | SCANNER_URL = "https://scan.example.com"SCANNER_TOKEN = "abc123def456" |
| 7 | Hard‑coded credentials in a third‑party SDK initialization | SDK init class | MySdk.init(context, "APP_ID", "APP_SECRET") |
Each of these patterns exposes a secret that can be extracted by reverse‑engineering the binary or by simply browsing the source repository.
---
4. Detecting hardcoded credentials
- Static code analysis – tools such as SonarQube, Semgrep, or GitGuardian scan the repository for literal strings that match typical secret patterns (
[A-Za-z0-9+/]{20,}=*,password=,api_key=). - Binary inspection – for Android APKs, use apktool to decompile and grep for Base64 blobs or plain passwords. For iOS, run class‑dump or otool on the binary.
- Secret‑scan CI integration – configure GitHub Actions or GitLab CI to invoke Gitleaks on every push; it flags patterns like
SCANNER_TOKENorBASIC_AUTH. - Runtime instrumentation – attach a Frida script to the running app to intercept network calls and log request headers; unexpected
Authorization:headers often reveal embedded credentials. - Configuration audit – verify that all environment‑specific files (
.env,config.yaml) are excluded from the public repo and that secret‑management tools are referenced via environment variables ($SCANNER_TOKEN).
When a detection tool reports a match, the next step is to confirm whether the value is truly a credential (e.g., a token) or a non‑secret constant (e.g., a UI label).
---
5. Fixing each example
1. strings.xml literal
- Fix: Move the key to a secure vault and read it at runtime.
- Code change:
val apiKey = System.getenv("SCANNER_API_KEY") ?: error("Missing API key")
2. Hard‑coded Basic Auth in code
- Fix: Use a credential store or environment variable.
- Code change:
String username = System.getenv("SCANNER_USER");
String password = System.getenv("SCANNER_PASS");
String credential = username + ":" + password;
3. Info.plist entry
- Fix: Remove the entry and inject the value via a provisioning profile or secure key‑chain item.
- Implementation:
if let token = ProcessInfo.processInfo.environment["SCANNER_TOKEN"] {
// use token
}
4. credentials.json in assets
- Fix: Delete the file and replace it with a call to a secrets manager.
- Approach:
val cred = SecretsManager.get("document_scanner_creds")
5. Dockerfile ENV variables
- Fix: Pass secrets at container start time rather than baking them into the image.
- Docker run example:
docker run -e SCANNER_USER=scanadmin -e SCANNER_PASS=scan123 my-scanner-image
6. Credentials in a public repo
- Fix: Immediately rotate the exposed secret, then remove the file and add it to
.gitignore. Use a secret‑scan tool to purge the history.
7. Hard‑coded SDK credentials
- Fix: Upgrade the SDK to a version that supports external token injection, or wrap the init call with a runtime fetch.
- Example:
String sdkAppId = System.getenv("SCANNER_SDK_ID");
String sdkSecret = System.getenv("SCANNER_SDK_SECRET");
MySdk.init(context, sdkAppId, sdkSecret);
In each case, the common pattern is “read from a protected source at runtime, never embed the literal.”
---
6. Prevention before release
- Enforce secret‑management policies – require all credentials to be sourced from a vault; CI pipelines must fail if a secret is detected in source files.
- Automated secret‑scan gates – integrate Gitleaks, TruffleHog, or Semgrep into every pull‑request workflow.
- Runtime secret verification – during pre‑release testing, run a Frida or Objection script that logs any
Authorizationheader containing hard‑coded patterns. - Code review checklist – add a line item “No literal credentials in code or resource files.”
- Container image scanning – use tools like Trivy or Anchore to scan Docker images for embedded secrets before pushing to a registry.
- Post‑deployment monitoring – enable SUSA‑style autonomous testing to continuously probe the app for unexpected authentication failures that could indicate a leaked credential.
By embedding these safeguards into the development lifecycle, document‑scanning products can avoid the costly fallout of hardcoded credentials and maintain the trust required for handling sensitive paperwork.
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free