Weakness reference
CWE-200

Exposure of Sensitive Information to an Unauthorized Actor

This weakness occurs when an application unintentionally reveals sensitive data—such as passwords, API keys, personal information, or internal system…

01Summary

This weakness occurs when an application unintentionally reveals sensitive data—such as passwords, API keys, personal information, or internal system details—to someone who should not have access to it. The exposure can happen through error messages, log files, HTTP responses, client-side code, or any other observable channel. Even a single leaked credential or system path can become a foothold for further attacks.

02How It Happens

Developers often prioritize functionality over information control, leaving sensitive data visible in places they assume only trusted users will see. Common patterns include: embedding secrets in client-side code or configuration files, returning detailed error messages that reveal database structure or file paths, logging sensitive values without redaction, or failing to restrict access to files containing credentials. The weakness is compounded when developers assume "security through obscurity"—that hiding something is the same as protecting it—rather than implementing proper access controls and data minimization.

03Real-World Impact

Exposed credentials allow attackers to impersonate legitimate users or systems, escalate privileges, or move laterally within a network. Leaked API keys enable unauthorized API calls, potentially leading to data theft or service abuse. Exposed file paths and system details reduce the attacker's reconnaissance time and increase the success rate of targeted exploits. Personal information leaks can result in identity theft, regulatory fines (GDPR, CCPA), and reputational damage. In many cases, the initial breach begins not with a sophisticated exploit but with a carelessly exposed secret found in a public repository, error page, or log file.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import logging
import sqlite3

# Logging without redaction
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

def authenticate_user(username, password):
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    
    # Sensitive data logged in plaintext
    logger.debug(f"Attempting login for user: {username}, password: {password}")
    
    cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
    user = cursor.fetchone()
    
    if user and user[2] == password:
        logger.info(f"Login successful for {username}")
        return True
    
    # Error message reveals database structure
    raise Exception(f"Query failed: SELECT * FROM users WHERE username = '{username}'")

Why it's vulnerable:
Passwords and query structure are logged and exposed in error messages, making them visible to anyone with access to logs or error output.

Fixed pattern
import logging
import sqlite3
import hashlib

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def authenticate_user(username, password):
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    
    # Log only non-sensitive identifiers
    logger.info(f"Authentication attempt for user ID: {username}")
    
    cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
    user = cursor.fetchone()
    
    if user and hashlib.sha256(password.encode()).hexdigest() == user[2]:
        logger.info("Authentication successful")
        return True
    
    # Generic error message; details logged separately at DEBUG level only
    logger.debug("Authentication failed: invalid credentials")
    raise Exception("Authentication failed")
Vulnerable pattern
<?php
// Error reporting exposes sensitive paths and database details
ini_set('display_errors', 1);
error_reporting(E_ALL);

$db_host = 'localhost';
$db_user = 'admin';
$db_pass = 'SecurePass123!';  // Hardcoded in source

$conn = mysqli_connect($db_host, $db_user, $db_pass, 'myapp_db');

if (!$conn) {
    // Full error message reveals database credentials and structure
    die("Connection failed: " . mysqli_connect_error());
}

$user_input = $_GET['id'];
$query = "SELECT * FROM users WHERE id = $user_input";
$result = mysqli_query($conn, $query);

if (!$result) {
    // Query exposed in error output
    echo "Error: " . mysqli_error($conn) . " | Query: " . $query;
}
?>

Why it's vulnerable:
Database credentials are hardcoded, error messages expose queries and connection details, and sensitive information is displayed directly to users.

Fixed pattern
<?php
// Suppress error display in production
ini_set('display_errors', 0);
error_reporting(E_ALL);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/app_errors.log');

// Load credentials from environment or secure config file
$db_host = getenv('DB_HOST');
$db_user = getenv('DB_USER');
$db_pass = getenv('DB_PASS');

$conn = mysqli_connect($db_host, $db_user, $db_pass, 'myapp_db');

if (!$conn) {
    // Log details securely; show generic message to user
    error_log("Database connection failed: " . mysqli_connect_error());
    die("A system error occurred. Please contact support.");
}

$user_input = $_GET['id'];
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $user_input);
$stmt->execute();
$result = $stmt->get_result();

if (!$result) {
    error_log("Query execution failed for user query");
    die("A system error occurred. Please contact support.");
}
?>

05Prevention Checklist

Minimize logged data:
Never log passwords, tokens, API keys, or full credit card numbers. Log only non-sensitive identifiers (user ID, session ID, timestamp).
Redact sensitive output:
Strip or mask secrets before displaying error messages, stack traces, or debug output to end users. Log full details only to secure, access-restricted files.
Store secrets securely:
Use environment variables, secure vaults, or configuration management tools—never hardcode credentials in source code or configuration files.
Disable verbose error reporting in production:
Set display_errors to 0 and log errors to a file with restricted access, not to the browser.
Review client-side code:
Audit JavaScript, HTML comments, and bundled assets for embedded API keys, internal URLs, or other sensitive metadata.
Restrict file and log access:
Ensure only authorized users can read log files, backup files, and configuration files containing sensitive data.

06Signs You May Already Be Affected

Check your application logs, error pages, and publicly accessible files (e.g., .git directories, backup files, JavaScript bundles) for exposed credentials, database connection strings, or internal system paths. Search your version control history for accidentally committed secrets using tools like git log or automated secret scanners. Review access logs for unusual patterns of file or log access that might indicate an attacker has discovered and is exploiting exposed information.

07Related Recent Vulnerabilities