Weakness reference
CWE-219

Storage of File Under Web Root with Sensitive Data

This weakness occurs when an application stores sensitive information—such as database credentials, API keys, private keys, or user data—in files placed within…

01Summary

This weakness occurs when an application stores sensitive information—such as database credentials, API keys, private keys, or user data—in files placed within the web-accessible directory. Because these files are under the web root, they can be retrieved directly via HTTP requests, bypassing any application-level access controls. An attacker who discovers or guesses the file path can download the sensitive data without authentication.

02How It Happens

Developers sometimes store configuration files, backups, or temporary data in directories that are meant to be served by the web server. This happens when the distinction between "files the application needs to read" and "files the web server should serve" becomes blurred. Common scenarios include:

- Placing .env files, config.php, or settings.ini in the document root or a subdirectory - Storing database dumps or CSV exports in a publicly accessible uploads/ or backups/ folder - Leaving private keys, certificates, or credentials in a keys/ or certs/ directory under the web root - Committing sensitive files to version control and deploying the entire .git/ directory to the server

The core issue is that the web server's document root is configured to serve everything within it, and no additional access control (file permissions, .htaccess rules, or application-level checks) prevents direct HTTP retrieval.

03Real-World Impact

An attacker can directly request the sensitive file via a browser or automated tool and receive its contents. This can lead to:

- Credential compromise:
Database passwords, API keys, or service account credentials exposed, allowing attackers to access backend systems. - Data breach:
Unencrypted user data, PII, or business information downloaded in bulk. - Account takeover:
Private keys or session tokens stolen and used to impersonate legitimate users or administrators. - Further exploitation:
Configuration details revealing internal architecture, software versions, or other systems that can be targeted.

04Vulnerable & Fixed Patterns

Vulnerable pattern
# app.py - Flask application
import os
from flask import Flask

app = Flask(__name__)

# Sensitive config stored in web root
config_file = os.path.join(app.root_path, 'config.ini')
with open(config_file, 'r') as f:
    DB_PASSWORD = f.read().strip()

@app.route('/data')
def get_data():
    return f"Database password: {DB_PASSWORD}"

Why it's vulnerable:
The config.ini file is placed in the Flask application root, which is typically served as the web root. An attacker can request http://example.com/config.ini directly and retrieve the credentials.

Fixed pattern
# app.py - Flask application
import os
from flask import Flask

app = Flask(__name__)

# Sensitive config stored OUTSIDE web root
config_file = '/etc/myapp/config.ini'  # or use environment variables
if os.path.exists(config_file):
    with open(config_file, 'r') as f:
        DB_PASSWORD = f.read().strip()
else:
    DB_PASSWORD = os.environ.get('DB_PASSWORD')

@app.route('/data')
def get_data():
    return "Data retrieved securely"
Vulnerable pattern
<?php
// index.php in web root
$config_file = __DIR__ . '/config.php';
include $config_file;

// config.php is in the same directory and web-accessible
// An attacker can request http://example.com/config.php directly
?>

Why it's vulnerable:
The config.php file containing database credentials is stored in the same directory as the public-facing PHP files. A direct HTTP request to /config.php will either execute it (exposing output) or, if the server misconfigures PHP handling, return its source code.

Fixed pattern
<?php
// index.php in web root
$config_file = '/etc/myapp/config.php';  // Outside web root
if (file_exists($config_file)) {
    include $config_file;
} else {
    $db_password = getenv('DB_PASSWORD');
}
?>

05Prevention Checklist

Store sensitive files outside the web root.
Place configuration, credentials, and private keys in directories that the web server cannot serve (e.g., /etc/, /opt/, or a parent directory above public_html/).
Use environment variables for secrets.
Load database passwords, API keys, and tokens from environment variables or a secure secrets manager, not from files.
Restrict file permissions.
Ensure configuration files are readable only by the application user, not by the web server process or other users.
Disable directory listing and file serving for sensitive paths.
Use .htaccess (Apache) or nginx configuration to deny direct access to any sensitive directories that must remain under the web root.
Audit your deployment.
Before deploying, verify that no .env, config.*, .git/, or backup files are present in the web-accessible directory.
Use a .gitignore file.
Prevent sensitive files from being committed to version control in the first place, and never deploy the .git/ directory to production.

06Signs You May Already Be Affected

Check your web server logs for HTTP requests to files like config.php, .env, settings.ini, backup.sql, or private.key. Unexpected 200 (success) responses to these requests suggest the files are accessible. Additionally, review your web root directory listing: if you see configuration files, database dumps, or private keys, they should be moved outside the web root immediately.