CWE-538: File and Directory Information Exposure
Overview
File and directory information exposure occurs when applications reveal sensitive file system metadata such as absolute paths, directory structures, file permissions, timestamps, or internal naming conventions. This information leakage typically manifests through error messages showing full file paths, directory listing pages, file metadata in HTTP headers, backup file discovery, or predictable file naming patterns. While not directly exploitable, this information aids attackers in reconnaissance, path traversal attacks, and understanding application architecture.
OWASP Classification
A01:2025 - Broken Access Control
Risk
Low to Medium: Exposed file paths reveal server configuration and application structure, enable more targeted path traversal attacks, disclose internal naming conventions allowing file enumeration, and expose backup or temporary files containing sensitive data. Combined with other vulnerabilities, this information significantly increases attack success rates.
Remediation Steps
Core principle: Never reveal internal file system paths, directory structures, or file metadata to untrusted users; use relative references and generic error messages.
Disable Directory Listings
Apache:
Nginx:
Express.js:
// VULNERABLE - enables directory browsing
app.use(express.static('public', { index: false, dotfiles: 'allow' }));
// SECURE - disable directory listing
app.use(express.static('public')); // Only serves files, not directories
Remove Path Information from Errors
# VULNERABLE - exposes full paths
try:
with open(f'/var/www/app/data/{file_id}.json') as f:
data = json.load(f)
except FileNotFoundError as e:
return str(e), 404 # Shows: "/var/www/app/data/12345.json not found"
# SECURE - generic error message
try:
with open(safe_file_path(file_id)) as f:
data = json.load(f)
except FileNotFoundError:
logger.error(f"File not found: {file_id}")
return {"error": "Resource not found"}, 404
Use Opaque File References
# VULNERABLE - predictable file naming
file_path = f'/uploads/{user_id}/document_{doc_id}.pdf'
# SECURE - random identifiers
import uuid
file_id = str(uuid.uuid4())
# Store mapping in database
db.save_file_mapping(doc_id=doc_id, storage_path=file_id)
# Later retrieval uses opaque ID
stored_path = db.get_file_path(doc_id)
Strip File Metadata
Remove or sanitize metadata from HTTP responses:
from flask import send_file
import os
@app.route('/download/<file_id>')
def download(file_id):
filepath = get_secure_path(file_id)
# Don't reveal internal file structure
return send_file(
filepath,
as_attachment=True,
download_name='document.pdf', # Generic name, not internal path
mimetype='application/pdf'
)
Protect Backup and Temporary Files
# Nginx - deny access to backup files
location ~* \.(bak|old|orig|save|swo|swp|tmp|temp)$ {
deny all;
}
# Deny common editor backup patterns
location ~ ~$ {
deny all;
}
Remove Server Version Headers
Implement Consistent File Access
# VULNERABLE - different error messages reveal file existence
if not os.path.exists(filepath):
return "File not found", 404
if not user.can_access(filepath):
return "Access denied", 403
# SECURE - same message for not-found and unauthorized
filepath = get_file_path(file_id)
if not filepath or not user.can_access(file_id):
return "Resource not found", 404 # Same message for both cases
Dynamic Scan Guidance
For guidance on remediating this CWE when detected by dynamic (DAST) scanners:
- Dynamic Scan Guidance - Analyzing DAST findings and mapping to source code