Skip to main content

Free 30-min security demo  — We'll scan your real code and show live findings, no commitment Book Now

Offensive360

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.

Offensive360 Security Research Team | | Vulnerability Research
hardcoded secretscredentialsAppSecsecrets managementCWE-798

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):

  1. Immediately invalidate the credential — rotate the password, revoke the API key
  2. Assume compromise — treat the credential as already stolen and audit for unauthorized access
  3. Remove from git history — use git filter-branch or BFG Repo Cleaner
  4. Scan all related systems — the same credential may be used elsewhere
  5. 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.

Written by Offensive360 Security Research Team

Find vulnerabilities before attackers do

Run Offensive360 SAST and DAST against your applications to catch security issues early.