Skip to content

CWE-259: Use of Hard-coded Password

Overview

Hard-coded passwords occur when credentials are embedded directly in source code, configuration files, or binaries. This exposes secrets to anyone with access to the codebase or distribution, making it easy for attackers to gain unauthorized access.

OWASP Classification

A07:2025 - Authentication Failures

Risk

Critical: Attackers can extract hard-coded credentials from code, version control, or binaries, leading to unauthorized access, privilege escalation, or full system compromise.

Remediation Steps

Core principle: Never embed secrets in application artifacts (source, images, configs, or client code); secrets must be injected at runtime from a dedicated secrets store and treated as replaceable, least-privilege credentials.

Locate the hard-coded password in your code

  • Review the flaw details to identify the specific file, line number, and code pattern
  • Search for hard-coded credentials: grep for "password=", "PASSWORD =", "secret=", "api_key="
  • Check configuration files: application.properties, config files, .env committed to version control
  • Inspect version control history: passwords may be in old commits

Remove hard-coded passwords (Primary Defense)

  • Never embed passwords in source code: Delete password string literals, constants with credentials
  • Use environment variables: Load passwords from environment: os.environ.get('DB_PASSWORD'), System.getenv("DB_PASSWORD")
  • Use secrets management tools: AWS Secrets Manager, Azure Key Vault, HashiCorp Vault, GCP Secret Manager
  • Remove from version control: Use .gitignore for credential files, remove from git history with BFG Repo-Cleaner or git-filter-repo
  • Use configuration management: Ansible Vault, Chef encrypted data bags, Kubernetes Secrets

Rotate and revoke exposed credentials immediately

  • Immediately rotate any credentials found in code: Change passwords in database, services, APIs
  • Revoke compromised API keys: Disable old keys, generate new ones
  • Audit access logs: Check for unauthorized access using exposed credentials
  • Notify affected parties: If customer credentials exposed, notify users to reset passwords
  • Update all environments: Change credentials in dev, staging, production

Use secure storage for secrets

  • Store in dedicated secret management systems: HashiCorp Vault (centralized), AWS Secrets Manager (cloud-native), Azure Key Vault, GCP Secret Manager
  • Restrict access based on least privilege: Grant secret access only to services that need them
  • Enable secret rotation: Automatically rotate secrets on schedule (quarterly, annually)
  • Audit secret access: Log who accessed which secrets and when
  • Use different secrets per environment: Different passwords for dev, staging, production

WARNING: .env files are NOT secure for production

.env files are acceptable for local development only but should never be used in production:

Why .env files are unsafe for production:

  • Stored as plaintext on disk - no encryption, readable by anyone with filesystem access
  • Easy to accidentally commit to version control despite .gitignore
  • No access control - can't restrict who reads which secrets
  • No audit trail - no logging of secret access or changes
  • No rotation support - requires file updates and redeployment
  • Vulnerable to path traversal - web server misconfigurations can expose them
  • Survives in git history - even if removed, they persist forever in version control

For local development:

  • .env files in .gitignore are acceptable for developer convenience
  • Use .env.example (with dummy values) in version control as a template

For production:

  • Use environment variables injected from secret management systems
  • Platform-specific: AWS Secrets Manager, Azure Key Vault, Kubernetes Secrets (encrypted at rest)
  • CI/CD systems: GitHub Actions secrets, GitLab CI/CD variables, Jenkins credentials
  • Never deploy .env files to production servers

Monitor and audit for secret exposure

  • Use automated tools to scan for hard-coded secrets: git-secrets, truffleHog, GitGuardian, Detect-Secrets
  • Regularly review code and configuration for accidental exposures (code reviews, security audits)
  • Set up pre-commit hooks: Prevent committing files with secrets
  • Monitor version control: Alert on commits containing potential secrets
  • Scan Docker images and artifacts: Check for secrets in container images, compiled binaries

Test the remediation thoroughly

  • Verify no hard-coded passwords remain in code (grep, secret scanning tools)
  • Test application loads secrets from environment variables or vault
  • Verify old hard-coded credentials no longer work (have been rotated)
  • Test secret rotation mechanisms work correctly
  • Check version control history is clean of secrets
  • Re-scan with security scanner to confirm the issue is resolved

Dynamic Scan Guidance

For guidance on remediating this CWE when detected by dynamic (DAST) scanners:

Common Vulnerable Patterns

  • Defining passwords as string literals in code
  • Including credentials in public repositories
  • Using default or sample passwords in production

Hard-coded Database Password (Python)

# Hard-coded password in code
DB_PASSWORD = 'SuperSecret123!'
connection = psycopg2.connect(
    host="localhost",
    database="mydb",
    user="admin",
    password="SuperSecret123!"  # Exposed in source code
)

Why this is vulnerable: Embedding passwords directly in source code exposes them to anyone with repository access, including in version control history, compiled binaries, and decompiled code, allowing attackers to extract credentials and gain unauthorized database access, often with elevated privileges.

Hard-coded API Key in Configuration (Java)

// API key embedded in source code
public class ApiClient {
    private static final String API_KEY = "sk_live_abc123xyz789";  // Exposed!

    public void makeRequest() {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.example.com/data"))
            .header("Authorization", "Bearer " + API_KEY)
            .build();
    }
}

Why this is vulnerable: Hard-coded API keys in source code are visible in version control, CI/CD logs, and decompiled bytecode, allowing attackers to extract the key and make unlimited API requests, potentially incurring charges, accessing sensitive data, or performing actions as the application.

Hard-coded AWS Credentials (JavaScript)

// AWS credentials in code
const AWS = require('aws-sdk');
AWS.config.update({
    accessKeyId: 'AKIAIOSFODNN7EXAMPLE',  // Exposed in repository
    secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',  // Critical exposure
    region: 'us-east-1'
});

Why this is vulnerable: Hard-coded AWS credentials in code grant full access to AWS resources with those credentials' permissions, and when exposed in repositories or client-side code, allow attackers to launch EC2 instances, access S3 buckets, delete resources, or rack up massive bills.

Hard-coded Password in Configuration File (Java Properties)

# application.properties committed to version control
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=MyP@ssw0rd123  # Exposed in config file

Why this is vulnerable: Configuration files committed to version control expose credentials to all developers with repository access, persist in git history even after deletion, and are often accidentally included in Docker images or deployment artifacts, making password compromise inevitable.

Hard-coded SMTP Credentials (C#)

// Email credentials in code
public class EmailService
{
    private const string SmtpUsername = "noreply@example.com";
    private const string SmtpPassword = "EmailPass123!";  // Exposed!

    public void SendEmail(string to, string subject, string body)
    {
        var client = new SmtpClient("smtp.example.com", 587)
        {
            Credentials = new NetworkCredential(SmtpUsername, SmtpPassword),
            EnableSsl = true
        };
    }
}

Why this is vulnerable: Hard-coded SMTP credentials allow attackers to send emails from the application's account, enabling spam campaigns, phishing attacks impersonating the organization, or email-based social engineering, while also exposing the credentials in compiled assemblies that can be reverse-engineered.

Secure Patterns

Environment Variable for Database Password (Python)

# Retrieve password from environment variable
import os
import psycopg2

DB_PASSWORD = os.environ.get('DB_PASSWORD')
if not DB_PASSWORD:
    raise ValueError('DB_PASSWORD environment variable not set')

connection = psycopg2.connect(
    host=os.environ.get('DB_HOST', 'localhost'),
    database=os.environ.get('DB_NAME', 'mydb'),
    user=os.environ.get('DB_USER', 'admin'),
    password=DB_PASSWORD
)

Why this works:

  • Separates secrets from code, preventing exposure in version control or compiled binaries
  • Allows different credentials per environment (dev/staging/production) without code changes
  • Enables credential rotation without redeploying application code
  • Removes secrets from version control history and distributed artifacts
  • Fails explicitly if secret is missing rather than using a default or empty value

AWS Secrets Manager Integration (Java)

import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ApiClient {
    private final String apiKey;

    public ApiClient() {
        // Retrieve API key from AWS Secrets Manager
        SecretsManagerClient client = SecretsManagerClient.create();
        GetSecretValueRequest request = GetSecretValueRequest.builder()
            .secretId("prod/api/key")
            .build();

        GetSecretValueResponse response = client.getSecretValue(request);
        this.apiKey = response.secretString();
    }

    public void makeRequest() {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.example.com/data"))
            .header("Authorization", "Bearer " + apiKey)
            .build();
    }
}

Why this works:

  • Retrieves secrets from AWS Secrets Manager at runtime, never storing them in code
  • Supports automatic secret rotation through AWS managed policies
  • Uses IAM roles for authentication, eliminating need for hard-coded AWS credentials
  • Secrets are encrypted at rest and in transit
  • Enables centralized secret management and auditing across applications

Environment Variables with Default Profile (JavaScript)

// Load AWS credentials from environment or IAM role
const AWS = require('aws-sdk');

// Uses credential chain: environment vars -> IAM role -> config file
// Never hard-code credentials
const s3 = new AWS.S3({
    region: process.env.AWS_REGION || 'us-east-1'
});

// Credentials automatically loaded from:
// - AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY env vars
// - IAM role (when running on EC2/ECS/Lambda)
// - ~/.aws/credentials file (local development only)

Why this works:

  • Uses AWS SDK credential chain to automatically discover credentials securely
  • Prefers IAM roles (best practice) over environment variables
  • No credentials in source code, configuration files, or version control
  • Different environments automatically use appropriate credential sources
  • Supports temporary credentials with automatic rotation

External Configuration File (Java Spring)

application.yml
// application.yml/application.properties - NOT committed to version control
// Instead, use environment-specific files loaded at runtime

// (checked into git - no secrets)
spring:
  datasource:
    url: ${DB_URL}
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
  mail:
    host: ${SMTP_HOST}
    port: ${SMTP_PORT}
    username: ${SMTP_USERNAME}
    password: ${SMTP_PASSWORD}

// Secrets loaded from:
// - Environment variables (production)
// - application-local.yml (local dev, in .gitignore)
// - Kubernetes secrets (K8s deployment)
// - AWS Systems Manager Parameter Store

Why this works:

  • Configuration references environment variables, not actual secrets
  • Secrets injected at deployment time through platform-specific mechanisms
  • Development environment uses local config file excluded from version control
  • Production uses environment variables or secret management service
  • Clear separation between code, configuration, and secrets

Azure Key Vault Integration (C#)

using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using System.Net.Mail;

public class EmailService
{
    private readonly string _smtpUsername;
    private readonly string _smtpPassword;

    public EmailService()
    {
        // Retrieve secrets from Azure Key Vault
        var keyVaultUrl = Environment.GetEnvironmentVariable("KEY_VAULT_URL");
        var client = new SecretClient(
            new Uri(keyVaultUrl),
            new DefaultAzureCredential()  // Uses managed identity
        );

        _smtpUsername = client.GetSecret("smtp-username").Value.Value;
        _smtpPassword = client.GetSecret("smtp-password").Value.Value;
    }

    public void SendEmail(string to, string subject, string body)
    {
        var client = new SmtpClient("smtp.example.com", 587)
        {
            Credentials = new NetworkCredential(_smtpUsername, _smtpPassword),
            EnableSsl = true
        };
        // Send email
    }
}

Why this works:

  • Retrieves secrets from Azure Key Vault at runtime using managed identity
  • No credentials needed to access Key Vault (uses Azure AD authentication)
  • Secrets centrally managed with access policies and audit logs
  • Supports secret versioning and automatic rotation
  • Encrypts secrets at rest and in transit

Additional Resources