Cleartext Storage in a File or on Disk

Description

Cleartext Storage in a File or on Disk is a vulnerability that occurs when a product stores sensitive information in cleartext in files or directly on disk storage. This includes configuration files, log files, data files, and any other persistent storage. Sensitive information such as passwords, API keys, encryption keys, personal data, and credentials can be read by attackers who gain access to the file system through legitimate access, misconfiguration, directory traversal vulnerabilities, or physical access to storage media. Even encoded (non-human-readable) information provides minimal protection, as attackers can easily determine the encoding method and decode the data.

Risk

Cleartext file storage creates persistent exposure of sensitive data across multiple attack vectors. Configuration files with plaintext credentials are frequently exposed through web server misconfigurations, backup leaks, source code repository commits, or directory traversal vulnerabilities. Log files containing sensitive data may be accessible to support personnel, log aggregation systems, or stored in less-secure archival systems. Physical access to storage media through stolen devices, improper disposal, or data center compromise exposes all cleartext data. Decrypted copies of sensitive data written temporarily to disk may persist even after the application deletes them due to file system behavior. The long-term persistence of files means exposures can affect data from years of operation.

Solution

Encrypt all sensitive data before writing to files or disk. Use strong encryption algorithms (AES-256) with proper key management for configuration file secrets. Consider using dedicated secrets management solutions (HashiCorp Vault, AWS Secrets Manager) instead of file-based credential storage. Implement environment variables or encrypted configuration for database credentials and API keys. For log files, implement filtering or masking to prevent sensitive data from being logged. Configure proper file permissions restricting access to necessary accounts only. Use full-disk encryption as an additional layer of protection. Ensure temporary files containing sensitive data are securely deleted using secure erasure methods. Audit file storage locations for sensitive data exposure.

Common Consequences

ImpactDetails
ConfidentialityScope: Confidentiality

Attackers with file system access can read sensitive information directly. Physical or administrative access to raw disk storage exposes all cleartext data regardless of file permissions.

Example Code

Vulnerable Code (Java/ASP.NET)

The following examples demonstrate cleartext file storage vulnerabilities:

// Vulnerable: Java properties file with cleartext credentials
// webapp.properties file content:
// webapp.ldap.username=secretUsername
// webapp.ldap.password=secretPassword
// db.connection.password=DatabasePass123

import java.io.FileOutputStream;
import java.util.Properties;

public class VulnerableConfigWriter {

    public void saveConfiguration(String dbHost, String dbUser, String dbPassword) {
        Properties props = new Properties();

        props.setProperty("db.host", dbHost);
        props.setProperty("db.user", dbUser);
        // Vulnerable: Plaintext password in properties file
        props.setProperty("db.password", dbPassword);

        try (FileOutputStream out = new FileOutputStream("config.properties")) {
            props.store(out, "Database Configuration");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Vulnerable: Writing decrypted data to file
    public void processEncryptedFile(String encryptedFile, String outputFile) {
        byte[] encrypted = readFile(encryptedFile);
        byte[] decrypted = decrypt(encrypted);

        // Vulnerable: Decrypted sensitive data written to disk!
        writeFile(outputFile, decrypted);
        // Even if deleted later, data may be recoverable
    }
}
<!-- Vulnerable: ASP.NET configuration with cleartext credentials -->
<!-- web.config -->
<configuration>
  <connectionStrings>
    <!-- Vulnerable: Cleartext database credentials -->
    <add name="ProductionDB"
         connectionString="Server=prod-db.example.com;Database=AppDB;uid=admin;pwd=SuperSecretPassword123;"
         providerName="System.Data.SqlClient" />
  </connectionStrings>

  <appSettings>
    <!-- Vulnerable: API keys in cleartext -->
    <add key="Stripe.ApiKey" value="sk_live_abcd1234efgh5678" />
    <add key="AWS.SecretKey" value="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" />
  </appSettings>
</configuration>
# Vulnerable: Python writing credentials to file
import json

def vulnerable_save_config(config_dict, filepath):
    # Vulnerable: Plaintext credentials in JSON file
    config = {
        'database': {
            'host': config_dict['db_host'],
            'user': config_dict['db_user'],
            'password': config_dict['db_password'],  # Plaintext!
            'port': 5432
        },
        'api_keys': {
            'stripe': config_dict['stripe_key'],  # Plaintext!
            'sendgrid': config_dict['sendgrid_key']
        }
    }

    with open(filepath, 'w') as f:
        json.dump(config, f, indent=2)

    # File permissions often default to world-readable!

# Vulnerable: Logging sensitive data to file
def vulnerable_log_request(request_data, logfile):
    log_entry = {
        'timestamp': datetime.now().isoformat(),
        'user': request_data.get('username'),
        'password': request_data.get('password'),  # Plaintext password in log!
        'credit_card': request_data.get('card_number'),
        'action': request_data.get('action')
    }

    with open(logfile, 'a') as f:
        f.write(json.dumps(log_entry) + '\n')

Fixed Code (Java/ASP.NET)

// Fixed: Encrypted configuration storage
import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.*;
import java.io.*;

public class SecureConfigWriter {

    private final SecretKey encryptionKey;

    public SecureConfigWriter(SecretKey key) {
        this.encryptionKey = key;
    }

    public void saveConfiguration(String dbHost, String dbUser, String dbPassword) {
        Properties props = new Properties();

        props.setProperty("db.host", dbHost);
        props.setProperty("db.user", dbUser);
        // Fixed: Encrypt sensitive values
        props.setProperty("db.password.encrypted", encryptValue(dbPassword));

        try (FileOutputStream out = new FileOutputStream("config.properties")) {
            props.store(out, "Database Configuration");
        } catch (Exception e) {
            throw new RuntimeException("Failed to save config", e);
        }

        // Fixed: Set restrictive file permissions
        setRestrictivePermissions("config.properties");
    }

    private String encryptValue(String value) {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            byte[] iv = new byte[12];
            SecureRandom.getInstanceStrong().nextBytes(iv);
            cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, new GCMParameterSpec(128, iv));
            byte[] encrypted = cipher.doFinal(value.getBytes());

            byte[] combined = new byte[iv.length + encrypted.length];
            System.arraycopy(iv, 0, combined, 0, iv.length);
            System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);

            return Base64.getEncoder().encodeToString(combined);
        } catch (Exception e) {
            throw new RuntimeException("Encryption failed", e);
        }
    }

    // Fixed: Process encrypted data in memory only
    public byte[] processEncryptedFile(String encryptedFile) {
        byte[] encrypted = readFile(encryptedFile);
        byte[] decrypted = decrypt(encrypted);

        // Fixed: Process in memory, never write decrypted to disk
        byte[] result = processData(decrypted);

        // Fixed: Clear sensitive data from memory
        Arrays.fill(decrypted, (byte) 0);

        return result;
    }
}

// Fixed: Use environment variables for credentials
public class SecureConfiguration {

    public String getDatabasePassword() {
        // Fixed: Read from environment, not file
        String password = System.getenv("DB_PASSWORD");
        if (password == null) {
            throw new IllegalStateException("DB_PASSWORD not set");
        }
        return password;
    }

    // Fixed: Use secrets manager
    public String getApiKey(String keyName) {
        SecretsManager client = SecretsManagerClient.create();
        GetSecretValueRequest request = GetSecretValueRequest.builder()
            .secretId(keyName)
            .build();
        return client.getSecretValue(request).secretString();
    }
}
<!-- Fixed: ASP.NET with encrypted configuration -->
<!-- web.config -->
<configuration>
  <connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">
    <!-- Fixed: Connection strings encrypted using DPAPI -->
    <EncryptedData>
      <CipherData>
        <CipherValue>AQAAANCMnd8BFdERjHoAwE...</CipherValue>
      </CipherData>
    </EncryptedData>
  </connectionStrings>

  <!-- Fixed: Use Azure Key Vault or similar for secrets -->
  <appSettings>
    <add key="Stripe.ApiKey" value="@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/StripeKey)" />
  </appSettings>
</configuration>

<!-- To encrypt: aspnet_regiis -pe "connectionStrings" -app "/MyApp" -->
# Fixed: Secure configuration handling
import os
import json
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

class SecureConfigManager:
    def __init__(self, encryption_key):
        self.aesgcm = AESGCM(encryption_key)

    def save_config(self, config_dict, filepath):
        # Fixed: Separate non-sensitive and sensitive data
        public_config = {
            'database': {
                'host': config_dict['db_host'],
                'port': 5432
            }
        }

        # Fixed: Encrypt sensitive values
        sensitive = {
            'db_user': config_dict['db_user'],
            'db_password': config_dict['db_password'],
            'api_keys': config_dict.get('api_keys', {})
        }

        nonce = os.urandom(12)
        encrypted = self.aesgcm.encrypt(
            nonce,
            json.dumps(sensitive).encode(),
            None
        )

        public_config['encrypted_secrets'] = base64.b64encode(
            nonce + encrypted
        ).decode()

        with open(filepath, 'w') as f:
            json.dump(public_config, f)

        # Fixed: Restrict file permissions
        os.chmod(filepath, 0o600)

# Fixed: Use environment variables
def get_secure_config():
    return {
        'db_host': os.environ.get('DB_HOST', 'localhost'),
        'db_user': os.environ.get('DB_USER'),
        'db_password': os.environ.get('DB_PASSWORD'),  # From environment
        'api_keys': {
            'stripe': os.environ.get('STRIPE_API_KEY')
        }
    }

# Fixed: Secure logging without sensitive data
def secure_log_request(request_data, logfile):
    log_entry = {
        'timestamp': datetime.now().isoformat(),
        'user': request_data.get('username'),
        'password': '[REDACTED]',  # Never log passwords
        'credit_card': mask_card(request_data.get('card_number')),
        'action': request_data.get('action')
    }

    with open(logfile, 'a') as f:
        f.write(json.dumps(log_entry) + '\n')

def mask_card(card_number):
    if card_number and len(card_number) >= 4:
        return '*' * (len(card_number) - 4) + card_number[-4:]
    return '[REDACTED]'

The fix encrypts sensitive data before storage, uses environment variables or secrets managers, and restricts file permissions.


Exploited in the Wild

World-Readable Credential Files (Various Systems, 2001)

CVE-2001-1481 documented systems storing credentials in cleartext within world-readable files, allowing any local user to read sensitive credentials.

Configuration File Password Exposure (Enterprise Applications, 2005)

CVE-2005-1828 and CVE-2005-2209 documented enterprise applications storing database and administrative passwords in cleartext configuration files.

Private Key in Log File (Security Software, 2004)

CVE-2004-2397 documented security software writing cleartext private keys and passphrases to log files.


Tools to Test/Exploit

  • TruffleHog — Scans file systems and repositories for secrets.

  • GitLeaks — Detects secrets in files and git history.

  • Grep — Simple pattern matching for common credential patterns in files.


CVE Examples


References

  1. MITRE Corporation. "CWE-313: Cleartext Storage in a File or on Disk." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/313.html

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

  3. OWASP Foundation. "Logging Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html