How to Prevent Hardcoded Passwords in Source Code
Hardcoded credentials in source code are one of the most common and most damaging vulnerability patterns. Here's how they end up in code and how to prevent them systematically.
Hardcoded passwords — credentials embedded directly in source code — are classified as CWE-798 and consistently appear in OWASP Top 10 discussions. Despite being well-understood for decades, they remain one of the most common findings in security assessments.
What Are Hardcoded Passwords?
Hardcoded credentials are plain-text usernames, passwords, API keys, or tokens embedded directly in source code. Unlike credentials stored in configuration files or environment variables, hardcoded credentials are baked into the application binary and cannot be changed without redeploying.
# VULNERABLE: Credential hardcoded in source
DATABASE_URL = "postgresql://admin:[email protected]/myapp"
API_KEY = "sk-live-abc123def456..."
def connect():
return psycopg2.connect(DATABASE_URL)
Why This Is So Dangerous
Anyone with code access has the credential. This includes every developer on the project, every contractor who has ever had repo access, and everyone who has ever cloned the repository — even if their access was later revoked.
Git history is permanent. If a credential is committed to a Git repository and later removed, it still exists in the commit history. Tools like git log -S "password" or truffleHog can recover it instantly.
Public repositories amplify the risk. GitHub, GitLab, and Bitbucket are automatically scanned by bots looking for credential patterns. A mistakenly public repository can result in credential theft within minutes of the push.
Default credentials are publicly known. Device firmware, IoT devices, and embedded systems with hardcoded default credentials are trivially compromised because the default password is documented in the product manual.
Common Locations for Hardcoded Credentials
- Application source code (database connections, API clients)
- Configuration files committed to version control
- Device firmware (BIOS, printers, network equipment)
- DevOps tooling (Ansible playbooks, Terraform configs, Helm charts)
- Mobile applications (API keys in APK/IPA files)
- Container images (credentials in Dockerfile RUN commands or ENV)
Prevention: Environment Variables
The most common fix is moving credentials to environment variables:
# SECURE: Credentials from environment
import os
DATABASE_URL = os.environ["DATABASE_URL"]
API_KEY = os.environ["API_KEY"]
# Or with a default for local development (never production)
DEBUG_MODE = os.getenv("DEBUG", "false").lower() == "true"
Environment variables are set at deployment time and never touch source code. They’re also easy to rotate — change the variable, restart the process.
Prevention: Secrets Management
For production systems, use a dedicated secrets manager:
# AWS Secrets Manager
import boto3
import json
def get_secret(secret_name):
client = boto3.client('secretsmanager')
response = client.get_secret_value(SecretId=secret_name)
return json.loads(response['SecretString'])
creds = get_secret("prod/myapp/database")
db_password = creds['password']
Popular secrets managers:
- AWS Secrets Manager — tight AWS integration, automatic rotation
- HashiCorp Vault — cloud-agnostic, powerful access policies
- Azure Key Vault — Azure-native
- Google Secret Manager — GCP-native
- Doppler / Infisical — developer-friendly SaaS options
Prevention: Configuration Files Outside Version Control
For local development, use a .env file that is always in .gitignore:
# .env (NEVER commit this)
DATABASE_URL=postgresql://...
API_KEY=sk-live-...
# .env.example (COMMIT this — shows required variables without values)
DATABASE_URL=
API_KEY=
Use dotenv libraries (Python: python-dotenv, Node: dotenv, etc.) to load these files locally.
Pre-Commit Scanning
Prevent credentials from reaching the repository with pre-commit hooks:
# Install detect-secrets
pip install detect-secrets
# Scan before each commit
detect-secrets scan > .secrets.baseline
pre-commit install
Tools like detect-secrets, truffleHog, and gitleaks can be run as pre-commit hooks or CI pipeline steps to catch credentials before they’re committed or merged.
What to Do When Credentials Are Exposed
If credentials are discovered in source code (or git history):
- Immediately invalidate the credential — rotate the password, revoke the API key
- Assume compromise — treat the credential as already stolen and audit for unauthorized access
- Remove from git history — use
git filter-branchor BFG Repo Cleaner - Scan all related systems — the same credential may be used elsewhere
- Post-mortem — understand how it was committed and add controls to prevent recurrence
How Offensive360 Detects This
Our SAST engine includes dedicated detection for hardcoded secrets: API key patterns, common password variable names, connection string patterns, and cryptographic key formats across all 30+ supported languages. Each finding includes the file path, line number, and the type of credential detected.
Related articles
Rust Vulnerabilities: Most Common Issues You Need to Know
While Rust provides memory safety advantages over C/C++, vulnerabilities still emerge — particularly when developers use unsafe code blocks or rely on libraries with security gaps.
OpenSSL Vulnerabilities CVE-2022-3602 and CVE-2022-3786: What You Need to Know
The OpenSSL Project disclosed two high-severity vulnerabilities in October 2022. Initially labeled critical, here's what they actually mean, who is affected, and what to do.
Spring4Shell — Critical Remote Code Execution in Spring Framework (CVE-2022-22965)
Spring4Shell is a critical RCE vulnerability (CVSS 9.8) affecting Spring MVC on JDK 9+. Here's what it is, whether you're affected, and how to patch it immediately.
Find vulnerabilities before attackers do
Run Offensive360 SAST and DAST against your applications to catch security issues early.