Exposure of Sensitive System Information to an Unauthorized Control Sphere
Description
Exposure of Sensitive System Information to an Unauthorized Control Sphere is a vulnerability where a product reveals sensitive system-level information to actors who do not have the same level of access as the product itself. Network-based products like web applications operate on top of operating systems and application servers but should conceal these underlying details from end users. Information such as file paths, operating system users, installed software packages, and application environment details may leak through product communications, diagnostic messages, error responses, or debugging output. Attackers exploit these details to understand system architecture and refine their attack strategies.
Risk
System information disclosure provides attackers with valuable reconnaissance data. Error responses revealing technologies, operating system versions, and product information enable targeting of known vulnerabilities specific to those versions. Stack traces expose implementation details, internal class names, and code structure. File paths reveal directory layouts that aid path traversal attacks. Database connection strings may include credentials. Environment variables might contain API keys or tokens. Process listings show running services and their configurations. This information asymmetry gives attackers significant advantages in planning and executing attacks.
Solution
Configure production systems to never expose internal details such as stack traces, debug messages, or verbose error information to end users. Implement generic, user-friendly error pages that log detailed information server-side only. Sanitize all error messages before display, removing paths, version numbers, and technical details. Use security headers to prevent information leakage. Ensure logging mechanisms don't expose sensitive data through log viewers. HTML entity-encode error messages written to logs to prevent XSS attacks against log viewing interfaces. Separate debug and production configurations.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Read Application Data - Sensitive system information disclosure allows attackers to understand the technology stack, identify potential vulnerabilities, and craft targeted attacks. |
| Other | Scope: Other Technical Impact: Reconnaissance - Exposed information aids attackers in mapping the system architecture and identifying attack vectors. |
Example Code
Vulnerable Code
// Vulnerable: Exposing stack traces to users
import javax.servlet.http.*;
import java.io.*;
public class VulnerableErrorServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException {
try {
processRequest(request);
} catch (Exception e) {
// Vulnerable: Full stack trace sent to client
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>An error occurred:</h1>");
out.println("<pre>");
e.printStackTrace(out); // Exposes internal details!
out.println("</pre>");
out.println("</body></html>");
}
}
// Vulnerable: Exposing system information
protected void showSystemInfo(HttpServletResponse response)
throws IOException {
PrintWriter out = response.getWriter();
// Vulnerable: Exposing PATH
out.println("PATH: " + System.getenv("PATH"));
// Vulnerable: Exposing user
out.println("User: " + System.getProperty("user.name"));
// Vulnerable: Exposing OS details
out.println("OS: " + System.getProperty("os.name") + " " +
System.getProperty("os.version"));
// Vulnerable: Exposing Java version
out.println("Java: " + System.getProperty("java.version"));
// Vulnerable: Exposing working directory
out.println("Dir: " + System.getProperty("user.dir"));
}
}
// Vulnerable: Database connection string in error messages
public class VulnerableDatabaseService {
private static final String CONNECTION_STRING =
"jdbc:mysql://db-server:3306/mydb?user=admin&password=secret123";
public void connect() {
try {
Connection conn = DriverManager.getConnection(CONNECTION_STRING);
} catch (SQLException e) {
// Vulnerable: Connection string with credentials logged/displayed
System.out.println("Failed to connect: " + CONNECTION_STRING);
throw new RuntimeException("Database error: " + e.getMessage() +
" Connection: " + CONNECTION_STRING);
}
}
}
# Vulnerable: Exposing system info in Python web app
from flask import Flask, request
import traceback
import os
import subprocess
app = Flask(__name__)
@app.route('/status')
def vulnerable_status():
# Vulnerable: Exposing environment variables
env_info = "<h2>Environment Variables:</h2><pre>"
for key, value in os.environ.items():
env_info += f"{key}={value}\n" # May include secrets!
env_info += "</pre>"
# Vulnerable: Exposing process list
try:
ps_output = subprocess.check_output(['ps', 'aux']).decode()
process_info = f"<h2>Running Processes:</h2><pre>{ps_output}</pre>"
except:
process_info = ""
return env_info + process_info
@app.errorhandler(500)
def vulnerable_error_handler(error):
# Vulnerable: Full traceback to client
return f"""
<html>
<body>
<h1>Internal Server Error</h1>
<h2>Traceback:</h2>
<pre>{traceback.format_exc()}</pre>
<h2>Request Details:</h2>
<pre>
Path: {request.path}
Method: {request.method}
Server: {request.host}
</pre>
</body>
</html>
""", 500
# Vulnerable: Debug mode in production
if __name__ == '__main__':
app.run(debug=True) # Never in production!
<?php
// Vulnerable: Exposing PHP info
function vulnerableDebugPage() {
// Vulnerable: Full PHP configuration exposed
phpinfo(); // Shows all PHP settings, paths, modules
}
// Vulnerable: Detailed error messages
function vulnerableQuery($userId) {
$conn = new mysqli("localhost", "root", "password123", "mydb");
$query = "SELECT * FROM users WHERE id = " . $userId;
if (!$result = $conn->query($query)) {
// Vulnerable: Query and connection details exposed
die("Query failed: " . $query .
"\nError: " . $conn->error .
"\nServer: " . $conn->server_info);
}
return $result;
}
// Vulnerable: Exception with system details
try {
include("/var/www/config/secret.php");
} catch (Exception $e) {
// Vulnerable: Full path exposed
echo "Error loading config: " . $e->getMessage();
echo "\nFile: " . $e->getFile();
echo "\nLine: " . $e->getLine();
echo "\nTrace: " . $e->getTraceAsString();
}
?>
Fixed Code
// Fixed: Secure error handling
import javax.servlet.http.*;
import java.io.*;
import java.util.logging.*;
public class SecureErrorServlet extends HttpServlet {
private static final Logger logger = Logger.getLogger(
SecureErrorServlet.class.getName()
);
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException {
try {
processRequest(request);
} catch (Exception e) {
// Fixed: Log detailed error server-side
String errorId = generateErrorId();
logger.log(Level.SEVERE,
"Error ID " + errorId + ": " + e.getMessage(), e);
// Fixed: Generic message to client
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>An error occurred</h1>");
out.println("<p>Please contact support with error ID: " +
escapeHtml(errorId) + "</p>");
out.println("</body></html>");
}
}
// Fixed: Never expose system information
protected void showStatus(HttpServletResponse response)
throws IOException {
PrintWriter out = response.getWriter();
// Fixed: Only expose necessary, non-sensitive info
out.println("Application Status: Running");
out.println("Version: 1.0");
out.println("Health: OK");
// Fixed: No paths, versions, users, or environment details
}
private String generateErrorId() {
return "ERR-" + System.currentTimeMillis() + "-" +
(int)(Math.random() * 10000);
}
private String escapeHtml(String input) {
return input.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace("\"", """);
}
}
// Fixed: Secure database service
public class SecureDatabaseService {
private static final Logger logger = Logger.getLogger(
SecureDatabaseService.class.getName()
);
// Fixed: Credentials from secure configuration
private String getConnectionString() {
return SecureConfig.getDatabaseUrl(); // No inline credentials
}
public void connect() {
try {
Connection conn = DriverManager.getConnection(getConnectionString());
} catch (SQLException e) {
// Fixed: Log full details server-side only
logger.log(Level.SEVERE, "Database connection failed", e);
// Fixed: Generic message, no connection details
throw new ServiceException("Database temporarily unavailable");
}
}
}
# Fixed: Secure error handling in Flask
from flask import Flask, request, render_template
import logging
import uuid
import os
app = Flask(__name__)
# Fixed: Configure secure logging
logging.basicConfig(
filename='/var/log/app/error.log',
level=logging.ERROR,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
@app.route('/status')
def secure_status():
# Fixed: Only expose safe, non-sensitive info
return {
"status": "healthy",
"version": "1.0.0",
"uptime": get_uptime_safe()
}
@app.errorhandler(500)
def secure_error_handler(error):
# Fixed: Generate error ID for tracking
error_id = str(uuid.uuid4())[:8]
# Fixed: Log full details server-side
logger.error(f"Error {error_id}: {error}", exc_info=True)
# Fixed: Generic message to client
return render_template('error.html', error_id=error_id), 500
@app.errorhandler(Exception)
def handle_exception(e):
error_id = str(uuid.uuid4())[:8]
logger.exception(f"Unhandled exception {error_id}")
# Fixed: Never expose exception details
return {
"error": "An unexpected error occurred",
"error_id": error_id,
"message": "Please contact support with this error ID"
}, 500
def get_uptime_safe():
# Fixed: Return sanitized uptime without system details
try:
with open('/proc/uptime', 'r') as f:
uptime_seconds = float(f.readline().split()[0])
return f"{int(uptime_seconds // 3600)} hours"
except:
return "unknown"
# Fixed: Never run with debug=True in production
if __name__ == '__main__':
debug_mode = os.environ.get('FLASK_DEBUG', 'false').lower() == 'true'
if os.environ.get('ENVIRONMENT') == 'production':
debug_mode = False # Force disable in production
app.run(debug=debug_mode)
<?php
// Fixed: Secure PHP configuration
ini_set('display_errors', 0); // Never display errors to users
ini_set('log_errors', 1); // Log errors instead
ini_set('error_log', '/var/log/php/error.log');
// Fixed: Custom error handler
function secureErrorHandler($errno, $errstr, $errfile, $errline) {
$errorId = uniqid('ERR-');
// Fixed: Log full details server-side
error_log("[$errorId] Error $errno: $errstr in $errfile:$errline");
// Fixed: Generic message to user
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
echo json_encode([
'error' => 'An error occurred',
'error_id' => $errorId,
'message' => 'Please contact support'
]);
return true; // Don't execute PHP's internal error handler
}
set_error_handler('secureErrorHandler');
// Fixed: Secure database queries
function secureQuery($userId) {
$conn = getSecureConnection(); // Connection from secure config
// Fixed: Prepared statement
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $userId);
if (!$stmt->execute()) {
$errorId = uniqid('DB-');
error_log("[$errorId] Database error: " . $stmt->error);
// Fixed: Generic message
throw new Exception("Database error. Reference: $errorId");
}
return $stmt->get_result();
}
// Fixed: Secure exception handling
try {
$config = loadSecureConfig();
} catch (Exception $e) {
$errorId = uniqid('CFG-');
// Fixed: Log details, show generic message
error_log("[$errorId] Config error: " . $e->getMessage() .
" in " . $e->getFile() . ":" . $e->getLine());
http_response_code(500);
echo "Configuration error. Reference: $errorId";
}
?>
CVE Examples
- CVE-2021-32638: Code analysis product exposed access tokens via command-line parameters or environment variables, making them visible through the
pscommand to other users on the same system.
References
- MITRE Corporation. "CWE-497: Exposure of Sensitive System Information to an Unauthorized Control Sphere." https://cwe.mitre.org/data/definitions/497.html
- OWASP. "Information Exposure Through Error Messages."
- OWASP. "Error Handling Cheat Sheet."