Weakness reference
CWE-538

Insertion of Sensitive Information into Externally-Accessible File or Directory

This weakness occurs when an application stores sensitive data—such as API keys, database credentials, private tokens, or user information—in a location that…

01Summary

This weakness occurs when an application stores sensitive data—such as API keys, database credentials, private tokens, or user information—in a location that is publicly accessible or readable by unauthorized users. The data itself may not be encrypted or protected, making it trivial for an attacker to discover and misuse it. This is one of the most common and easily exploitable vulnerabilities in web applications.

02How It Happens

Developers often inadvertently expose sensitive information by placing it in web-accessible directories (like public_html, www, or static asset folders), committing it to version control repositories that are later made public, or storing it in temporary files without proper access controls. Configuration files, backup copies, log files, and debug output are frequent culprits. The weakness is compounded when developers assume "security through obscurity"—hiding files with non-obvious names rather than restricting access at the filesystem or web server level. In many cases, the sensitive data is never meant to be in that location at all; it ends up there due to misconfiguration, incomplete cleanup, or a misunderstanding of where the application's web root actually is.

03Real-World Impact

Exposed credentials allow attackers to bypass authentication, access databases, or impersonate the application to third-party services. Leaked API keys can lead to unauthorized API calls, data exfiltration, or financial charges. Exposed private keys compromise encryption and digital signatures. Customer data, session tokens, or internal documentation in public directories can result in privacy violations, account takeovers, and further attacks. Even a single exposed configuration file can provide a complete roadmap for lateral movement within an infrastructure.

04Vulnerable & Fixed Patterns

Vulnerable pattern
# Vulnerable: storing secrets in a file within the web-accessible directory
import os

def save_config():
    config_data = {
        "db_password": "super_secret_123",
        "api_key": "sk_live_abcd1234efgh5678",
        "admin_token": "token_xyz789"
    }
    
    # File is placed in the static/public directory
    config_file = os.path.join("static", "config.json")
    with open(config_file, "w") as f:
        json.dump(config_data, f)

Why it's vulnerable:
The static/ directory is typically served directly by the web server, making config.json accessible via a direct HTTP request. Anyone who guesses or discovers the filename can retrieve all credentials.

Fixed pattern
# Fixed: store secrets outside the web root, use environment variables
import os
import json

def load_config():
    # Read from environment variables or a secure secrets manager
    config_data = {
        "db_password": os.environ.get("DB_PASSWORD"),
        "api_key": os.environ.get("API_KEY"),
        "admin_token": os.environ.get("ADMIN_TOKEN")
    }
    return config_data

# Alternatively, store in a file outside the web root with restricted permissions
def load_config_from_file():
    # /etc/app/secrets.json is outside web root, readable only by app user
    config_file = "/etc/app/secrets.json"
    with open(config_file, "r") as f:
        return json.load(f)
Vulnerable pattern
<?php
// Vulnerable: storing credentials in a file within the web root
$config = array(
    "db_host" => "localhost",
    "db_user" => "app_user",
    "db_password" => "password123",
    "api_secret" => "secret_key_abc"
);

// File saved in the web-accessible directory
file_put_contents("wp-content/config_backup.php", "<?php " . var_export($config, true));
?>

Why it's vulnerable:
The file is stored in wp-content/, which is within the web root and can be accessed directly via HTTP. Even if the .php extension prevents direct execution in some cases, the raw file contents may still be readable.

Fixed pattern
<?php
// Fixed: use environment variables or a file outside the web root
$db_password = getenv("DB_PASSWORD");
$api_secret = getenv("API_SECRET");

// Or load from a file outside the web root with restricted permissions
$config_file = "/var/app/secrets/config.php";
if (file_exists($config_file) && is_readable($config_file)) {
    $config = include($config_file);
} else {
    die("Configuration file not accessible.");
}
?>

05Prevention Checklist

Store secrets outside the web root.
Place configuration files, credentials, and keys in directories that are not served by the web server (e.g., /etc/app/, /var/app/secrets/, or a parent directory above public_html).
Use environment variables or a secrets manager.
Inject sensitive values at runtime via environment variables, a dedicated secrets vault (HashiCorp Vault, AWS Secrets Manager), or a .env file that is explicitly excluded from version control and the web root.
Restrict file permissions.
Ensure configuration files are readable only by the application user (e.g., chmod 600 on Unix/Linux). Use filesystem ACLs if available.
Never commit secrets to version control.
Add config.php, .env, secrets.json, and similar files to .gitignore. Use .gitignore templates for your framework and review commit history for accidental leaks.
Disable directory listing.
Configure your web server to deny directory listing (e.g., Options -Indexes in Apache, or autoindex off in Nginx) to prevent attackers from browsing for exposed files.
Scan for exposed files regularly.
Use automated tools to check for common sensitive filenames (e.g., config.php, settings.json, .env, backup.sql) in your web root and version control history.

06Signs You May Already Be Affected

Check your web server logs for requests to suspicious filenames like config.php, secrets.json, .env, or backup.sql. Search your web root and version control history for files containing keywords like password, api_key, secret, or token. Review your .gitignore file to confirm that configuration and credential files are properly excluded; if they are not, they may have been committed in the past and remain accessible to anyone with repository access.

07Related Recent Vulnerabilities