Description
Hardcoded credentials (CWE-798 — Use of Hard-coded Credentials) refers to the practice of embedding authentication secrets — passwords, API keys, tokens, private keys, encryption keys, or database connection strings — directly in source code, configuration files, scripts, or compiled binaries. These credentials are then distributed with the code and become accessible to anyone who can access the repository, decompile the application binary, or read the configuration.
This vulnerability is categorized under A02:2021 — Cryptographic Failures in the OWASP Top 10, reflecting that hardcoded credentials represent a fundamental failure to protect sensitive cryptographic material. It is consistently rated critical (CVSS 9.8) because exploitation requires no technical skill beyond a text search, and the resulting access is often to production systems, cloud infrastructure, or third-party APIs with broad permissions.
Hardcoded credentials appear across every platform: in PHP config files checked into GitHub, in Android APKs with embedded AWS keys, in iOS apps with hardcoded backend tokens, in Docker images pushed to public registries, in CI/CD pipeline configurations, and in network device firmware. The historical record of major breaches caused by exposed credentials in public repositories is extensive.
How It Works
The attacker's workflow is straightforward. For publicly accessible repositories:
# GitHub search for secrets
site:github.com "AKIA" "amazonaws.com" # AWS access keys
site:github.com "db_password" filename:.env
site:github.com "SECRET_KEY" filename:settings.py
# Using truffleHog
trufflehog github --org=<target_org> --only-verified
# Using gitleaks on a cloned repo
gitleaks detect --source=/path/to/repo --report-format=json
For mobile applications, the attacker decompiles an APK:
jadx -d output_dir/ app.apk
grep -r "api_key\|secret\|password\|token\|AWS\|AKIA" output_dir/
Common hardcoded credential patterns found in mobile apps include:
- AWS credentials (
AKIA...access key IDs) in Java/Kotlin strings - Firebase API keys with broad project permissions
- Stripe secret keys (
sk_live_...) instead of publishable keys - JWT signing secrets used to forge authentication tokens
- Internal API endpoint tokens
In compiled binaries (desktop apps, firmware), tools like strings, Ghidra, and Binwalk extract readable strings, while bingrep searches for patterns that look like secrets.
Git history is permanent. Even when a developer discovers and removes a hardcoded credential, the credential persists in the repository's commit history and is trivially recoverable:
git log --all --full-history -- config/secrets.py
git show <commit_hash>:config/secrets.py
Any credential that has ever been committed to a repository must be treated as compromised and rotated immediately, regardless of whether it has since been removed.
Impact
- Cloud infrastructure compromise — AWS, GCP, or Azure API keys enable resource creation, data access, and account takeover across the entire cloud account.
- Database exfiltration — hardcoded database credentials provide direct read/write access to all application data, including PII and financial records.
- Third-party service abuse — exposed Stripe, Twilio, SendGrid, or similar API keys enable fraudulent charges, spam campaigns, or data leaks on the vendor's platform.
- JWT forgery — exposed JWT signing secrets allow forging authentication tokens for any user, including administrators.
- Supply chain attacks — credentials in CI/CD pipelines or package manager configurations enable injection into build artifacts.
- Complete application takeover — administrative API keys or session signing secrets provide full control over the application.
Detection
- Scan all repositories with secret detection tools — run gitleaks (
gitleaks detect), truffleHog (trufflehog git), detect-secrets (Yelp), or Semgrep with secret detection rules across the full repository history, not just the current commit. - Search for high-entropy strings — tools like truffleHog use entropy analysis to find strings that look like randomly generated secrets even without pattern matching.
- Decompile mobile apps — use jadx (Android) and class-dump or Hopper (iOS) to extract strings from application binaries. Search for key patterns:
AKIA,sk_live_,ghp_,eyJ(JWT), connection strings. - Inspect Docker images — pull and inspect image layers with
docker history --no-trunc <image>anddive <image>. Each layer may contain credentials that were "deleted" in a later layer but remain in the image filesystem. - Review CI/CD pipeline configurations — check
.github/workflows/,.gitlab-ci.yml,Jenkinsfile, and.circleci/config.ymlfor hardcoded tokens or credentials passed as strings rather than secrets. - Check configuration and
.envfiles committed to the repository, including all branches and tags, not just the main branch.
Remediation
Use environment variables and secrets management. Never hardcode secrets in code. Load them from environment variables at runtime, or from a dedicated secrets manager:
import os
# Instead of: API_KEY = "sk_live_abc123..."
API_KEY = os.environ["STRIPE_API_KEY"]
# Or via a secrets manager (AWS Secrets Manager, HashiCorp Vault)
import boto3
secret = boto3.client("secretsmanager").get_secret_value(SecretId="prod/stripe")
Integrate secret scanning into CI/CD. Add a pre-commit hook with gitleaks or pre-commit + detect-secrets so secrets are caught before they reach the repository.
Rotate all exposed credentials immediately. Treat any credential that has been committed, even briefly, as fully compromised. Rotate it, audit for unauthorized usage, and enable alerts for future use of the old credential.
Use short-lived credentials where possible. AWS IAM roles with instance profiles, Workload Identity in GCP/Azure, and OIDC-based GitHub Actions secrets provide temporary, automatically rotated credentials that never appear in code.
Store secrets in a vault. HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, and Azure Key Vault provide centralized, audited, access-controlled secret storage with automatic rotation capabilities.
