Cleartext Storage of Sensitive Information in Executable

Description

Cleartext Storage of Sensitive Information in Executable is a vulnerability that occurs when a product stores sensitive information in cleartext within an executable binary. This includes passwords, encryption keys, API keys, private keys, and other secrets embedded directly in compiled code or stored in data sections of executables. Attackers can extract this information through reverse engineering, binary analysis, or simple string extraction from the executable file. Even when information is encoded (such as Base64), it provides no meaningful protection as attackers can easily identify and decode common encoding schemes.

Risk

Embedding sensitive information in executables creates severe, persistent security vulnerabilities. The distributed nature of executables means secrets are exposed to anyone with access to the binary file. Reverse engineering tools and techniques are widely available, making extraction straightforward even for moderately skilled attackers. Simple string searches often reveal passwords and keys stored as ASCII text. Embedded secrets cannot be rotated without redistributing the entire application. The vulnerability affects all instances of the application - a single binary analysis compromises every deployment. Real-world exploits have included embedded RSA private keys enabling server spoofing, hard-coded administration passwords, and SSH keys granting root access. The impact is amplified when executables are distributed to untrusted parties or made publicly available.

Solution

Never embed sensitive information directly in executable code or resources. Use external configuration files with proper access controls and encryption. Implement secure key management systems that provide keys at runtime rather than compile time. Use environment variables for credentials in deployment environments. Implement hardware security modules (HSMs) for cryptographic key storage in high-security applications. For applications requiring embedded authentication, use challenge-response protocols rather than static secrets. If some form of embedded secret is unavoidable, use white-box cryptography techniques to obfuscate keys, understanding this provides only defense in depth rather than true security. Implement code obfuscation as an additional layer but never rely on it alone. Use binary scanning tools during CI/CD to detect accidentally embedded secrets.

Common Consequences

ImpactDetails
ConfidentialityScope: Confidentiality

Attackers can extract sensitive information from executables through reverse engineering or string analysis, compromising encryption keys, passwords, API keys, and other secrets.
Access Control, AuthenticationScope: Access Control, Authentication

Exposed credentials enable unauthorized access. Compromised private keys allow server impersonation and man-in-the-middle attacks. All deployments using the same executable are equally compromised.

Example Code

Vulnerable Code (C/Java)

The following examples demonstrate cleartext executable storage vulnerabilities:

// Vulnerable: Hard-coded credentials in C executable
#include <stdio.h>
#include <string.h>

// Vulnerable: Password as string constant in binary
#define ADMIN_PASSWORD "SuperSecretAdmin123"

// Vulnerable: Encryption key embedded in code
static const unsigned char encryption_key[] = {
    0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
    0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
};

// Vulnerable: API key as string
static const char *API_KEY = "sk_live_51H2x3y4z5a6b7c8d9e0f1g2h3";

// Vulnerable: Database credentials embedded
static const char *DB_CONNECTION =
    "Server=prod.db.example.com;User=admin;Password=DbP@ss2024!;";

int authenticate(const char *password) {
    // Vulnerable: Comparing against embedded password
    if (strcmp(password, ADMIN_PASSWORD) == 0) {
        return 1;  // Authenticated
    }
    return 0;
}

void encrypt_data(unsigned char *data, size_t len) {
    // Vulnerable: Using embedded key
    aes_encrypt(data, len, encryption_key);
}

// Running 'strings' on this binary reveals:
// SuperSecretAdmin123
// sk_live_51H2x3y4z5a6b7c8d9e0f1g2h3
// Server=prod.db.example.com;User=admin;Password=DbP@ss2024!;
// Vulnerable: Hard-coded credentials in Java
public class VulnerableConfig {

    // Vulnerable: Password as constant
    private static final String ADMIN_PASSWORD = "AdminSecret2024!";

    // Vulnerable: API key embedded in class
    private static final String STRIPE_API_KEY = "sk_live_abcd1234efgh5678";

    // Vulnerable: Database credentials
    private static final String DB_URL =
        "jdbc:mysql://prod.db.example.com/app";
    private static final String DB_USER = "root";
    private static final String DB_PASSWORD = "RootP@ssw0rd!";

    // Vulnerable: Encryption key as byte array
    private static final byte[] AES_KEY = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
    };

    // Vulnerable: Comparing against hard-coded password
    public boolean authenticate(String password) {
        // Hash comparison doesn't help - hash is also embedded!
        if (password.equals("68af404b513073584c4b6f22b6c63e6b")) {
            return true;
        }
        return false;
    }

    public Connection getConnection() throws SQLException {
        // Vulnerable: Using embedded credentials
        return DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
    }
}
# Vulnerable: Python script compiled to executable
# (using PyInstaller, cx_Freeze, etc.)

# Vulnerable: Hard-coded credentials
AWS_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE"
AWS_SECRET_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

# Vulnerable: Embedded RSA private key
RSA_PRIVATE_KEY = """
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA0Z3VS5JJcds3xfn/ygWyf8Lsh...
-----END RSA PRIVATE KEY-----
"""

# Vulnerable: Database password
DB_CONFIG = {
    'host': 'db.production.example.com',
    'user': 'dbadmin',
    'password': 'ProductionDbPass123!',  # Embedded!
    'database': 'production_db'
}

class VulnerableAuth:
    # Vulnerable: Master password embedded
    MASTER_PASSWORD = "MasterSecretKey2024!"

    def authenticate(self, password):
        return password == self.MASTER_PASSWORD

Fixed Code (C/Java)

// Fixed: External credential retrieval in C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Fixed: Credentials retrieved from environment or secure storage
char* get_admin_password() {
    // Fixed: Read from environment variable
    char *password = getenv("ADMIN_PASSWORD");
    if (password == NULL) {
        fprintf(stderr, "ADMIN_PASSWORD not set\n");
        exit(1);
    }
    return password;
}

// Fixed: Key retrieved from secure storage at runtime
int get_encryption_key(unsigned char *key, size_t key_len) {
    // Option 1: Read from secure file with restricted permissions
    FILE *keyfile = fopen("/etc/myapp/secrets/encryption.key", "rb");
    if (keyfile == NULL) {
        return -1;
    }

    // File should be chmod 0600, owned by app user
    size_t read = fread(key, 1, key_len, keyfile);
    fclose(keyfile);

    return (read == key_len) ? 0 : -1;
}

// Fixed: API key from environment
char* get_api_key() {
    return getenv("API_KEY");
}

// Fixed: Database connection from secure config
char* get_db_connection() {
    // Read from encrypted config file or secrets manager
    return read_encrypted_config("database.connection");
}

int authenticate(const char *password) {
    // Fixed: Get password from secure source
    char *stored_password = get_admin_password();

    // Fixed: Constant-time comparison
    int result = constant_time_compare(password, stored_password);

    return result;
}

void encrypt_data(unsigned char *data, size_t len) {
    unsigned char key[16];

    // Fixed: Retrieve key at runtime
    if (get_encryption_key(key, sizeof(key)) != 0) {
        fprintf(stderr, "Failed to retrieve encryption key\n");
        return;
    }

    aes_encrypt(data, len, key);

    // Fixed: Clear key from memory after use
    explicit_bzero(key, sizeof(key));
}
// Fixed: External credential management in Java
import java.sql.*;
import java.io.*;
import java.nio.file.*;

public class SecureConfig {

    // Fixed: No embedded credentials!

    // Fixed: Retrieve password from environment
    public static String getAdminPassword() {
        String password = System.getenv("ADMIN_PASSWORD");
        if (password == null || password.isEmpty()) {
            throw new SecurityException("ADMIN_PASSWORD not configured");
        }
        return password;
    }

    // Fixed: Retrieve API key from secrets manager
    public static String getApiKey() {
        // Using AWS Secrets Manager, HashiCorp Vault, or similar
        SecretsClient client = SecretsClient.create();
        return client.getSecretValue("myapp/stripe_api_key");
    }

    // Fixed: Database credentials from secure source
    public static Connection getConnection() throws SQLException {
        // Fixed: Read from encrypted config or secrets manager
        String dbUrl = System.getenv("DB_URL");
        String dbUser = System.getenv("DB_USER");
        String dbPassword = getSecretFromVault("database/password");

        if (dbPassword == null) {
            throw new SecurityException("Database credentials not available");
        }

        return DriverManager.getConnection(dbUrl, dbUser, dbPassword);
    }

    // Fixed: Encryption key from secure key store
    public static byte[] getEncryptionKey() {
        try {
            // Read from secure file with restricted permissions
            Path keyPath = Paths.get("/etc/myapp/secrets/encryption.key");

            // Verify file permissions (Unix)
            // Should be readable only by application user

            return Files.readAllBytes(keyPath);
        } catch (IOException e) {
            throw new SecurityException("Cannot retrieve encryption key", e);
        }
    }

    // Fixed: Hash-based authentication without embedded hash
    public boolean authenticate(String password) {
        // Fixed: Retrieve stored hash from secure storage
        String storedHash = getStoredPasswordHash();

        // Fixed: Use secure password verification
        return BCrypt.checkpw(password, storedHash);
    }

    private String getStoredPasswordHash() {
        // Retrieve from secure database or config
        return secureConfig.get("auth.password_hash");
    }

    private static String getSecretFromVault(String secretPath) {
        // Implementation using HashiCorp Vault, AWS Secrets Manager, etc.
        VaultClient vault = VaultClient.create();
        return vault.readSecret(secretPath);
    }
}
# Fixed: External credential retrieval in Python
import os
from functools import lru_cache
import boto3  # For AWS Secrets Manager

class SecureConfig:
    """Configuration manager with external secret retrieval."""

    # Fixed: No embedded credentials!

    @staticmethod
    def get_admin_password():
        """Retrieve admin password from environment."""
        password = os.environ.get('ADMIN_PASSWORD')
        if not password:
            raise ValueError("ADMIN_PASSWORD environment variable not set")
        return password

    @staticmethod
    @lru_cache(maxsize=1)  # Cache to avoid repeated calls
    def get_aws_credentials():
        """Get AWS credentials from IAM role or environment."""
        # Use IAM roles when running in AWS
        # Falls back to environment variables
        session = boto3.Session()
        credentials = session.get_credentials()
        return credentials

    @staticmethod
    def get_api_key(key_name):
        """Retrieve API key from secrets manager."""
        client = boto3.client('secretsmanager')
        response = client.get_secret_value(SecretId=key_name)
        return response['SecretString']

    @staticmethod
    def get_db_config():
        """Get database configuration from secure source."""
        return {
            'host': os.environ.get('DB_HOST', 'localhost'),
            'user': os.environ.get('DB_USER'),
            'password': SecureConfig.get_api_key('myapp/db_password'),
            'database': os.environ.get('DB_NAME')
        }

    @staticmethod
    def get_encryption_key():
        """Retrieve encryption key from secure storage."""
        # Read from file with restricted permissions
        key_path = '/etc/myapp/secrets/encryption.key'

        # Verify file permissions
        import stat
        mode = os.stat(key_path).st_mode
        if mode & (stat.S_IRWXG | stat.S_IRWXO):
            raise PermissionError("Key file has insecure permissions")

        with open(key_path, 'rb') as f:
            return f.read()

# Fixed: Authentication without embedded secrets
class SecureAuth:
    def authenticate(self, password):
        stored_hash = self._get_stored_hash()
        return bcrypt.checkpw(password.encode(), stored_hash.encode())

    def _get_stored_hash(self):
        # Retrieve from secure database
        return database.get_password_hash(self.username)

The fix retrieves all sensitive data from external secure sources rather than embedding in code.


Exploited in the Wild

DLL-Embedded RSA Private Key (Network Software, 2005)

CVE-2005-1794 documented a product that stored an RSA private key directly in a DLL, enabling attackers to spoof the server and perform man-in-the-middle attacks against all users.

Executable Administration Passwords (Enterprise Software, 2001)

CVE-2001-1527 documented administration passwords stored in cleartext within executables, compromising all deployments of the software.


Tools to Test/Exploit

  • Strings — Extracts printable strings from binary files.

  • IDA Pro — Disassembler for reverse engineering binaries.

  • Ghidra — NSA's open-source reverse engineering suite.

  • TruffleHog — Scans for secrets in binaries and code.


CVE Examples


References

  1. MITRE Corporation. "CWE-318: Cleartext Storage of Sensitive Information in Executable." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/318.html

  2. OWASP Foundation. "Cryptographic Storage Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html

  3. NIST. "Key Management Guidelines." SP 800-57. https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final