Skip to content

OWASP ASVS 7.4.1: Error Handling Without Information Disclosure - Java, Python, JavaScript

In short OWASP ASVS 7.4.1 requires that a generic message is shown when an unexpected or security-sensitive error occurs, so responses do not expose stack traces, queries, file paths, or sensitive input. Prevent violations by catching unhandled exceptions in a global handler, logging the full exception internally with a correlation ID, and returning only that ID to the client.

OWASP ASVS requirement 7.4.1 addresses how applications respond when something goes wrong. A poorly handled error can return a full stack trace, database query, internal file path, or fragment of sensitive input back to the user - information attackers use to map the application’s internals and identify further vulnerabilities. 7.4.1 requires that error messages returned to users and written to logs be generic, consistent, and free of information disclosure.

This page explains the requirement, shows common violation patterns, and provides remediation code in Java, Python, and JavaScript.

ASVS v4.0.3: 7.4.1 Verify that a generic message is shown when an unexpected or security sensitive error occurs, potentially with a unique ID which support personnel can use to investigate.

ASVS 5.0 moves this to requirement 16.5.1, in the V16.5 Error Handling section, with equivalent intent: a generic message must be returned to the consumer, with no exposure of sensitive internal system data such as stack traces, queries, secret keys, and tokens.

Information leakage enables further attacks. A stack trace reveals framework versions, internal class names, file paths, and sometimes SQL fragments. Attackers use this to identify known vulnerabilities in specific library versions or to craft more targeted injection payloads.

Error messages often echo user input. A validation error for an email field might include the invalid value in the response: “Invalid email: [email protected]”. When that value contains sensitive data (a mistyped password in the email field, for example), the error response becomes a data exposure.

Logged errors propagate sensitive data. Unhandled exceptions caught by a top-level handler often log the full exception chain. If any link in that chain includes sensitive input, it gets written to the log - overlapping directly with ASVS 7.1.1.

The pattern is the same across languages: catch all unhandled exceptions at a global handler, generate a correlation ID, log the full exception internally with that ID, and return only the ID to the client. Implementation differs by framework:

  • Java: Centralize error handling through a @ControllerAdvice class (Spring) or a servlet-level error handler. Never return raw exception messages to the client.

  • Python: Register a global exception handler - @app.errorhandler(Exception) in Flask, app.add_exception_handler(Exception, handler) in FastAPI, or middleware with process_exception in Django.

  • JavaScript: Error-handling middleware must be the last middleware registered and must have an arity of four (err, req, res, next) to be recognized by Express as an error handler.

Java
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.http.ResponseEntity;
import java.util.UUID;
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handle(Exception ex) {
String errorId = UUID.randomUUID().toString();
// Log the full error internally with the correlation ID
logger.error("Unhandled exception [errorId={}]", errorId, ex);
// Return only the correlation ID to the user — no stack trace, no exception message
return ResponseEntity.status(500)
.body(new ErrorResponse("An unexpected error occurred", errorId));
}
}
Javascript
const express = require('express');
const { v4: uuidv4 } = require('uuid');
const winston = require('winston');
const app = express();
const logger = winston.createLogger({ /* ... */ });
// ... routes ...
// Error handler MUST have 4 parameters
app.use((err, req, res, next) => {
const errorId = uuidv4();
// Log full error internally
logger.error('Unhandled exception', { errorId, error: err.stack });
// Return only the correlation ID — no stack trace in production
res.status(500).json({
error: 'An unexpected error occurred',
errorId
});
});
Python
import logging
import uuid
from flask import Flask, jsonify
app = Flask(__name__)
logger = logging.getLogger(__name__)
@app.errorhandler(Exception)
def handle_exception(ex):
error_id = str(uuid.uuid4())
# Log full details server-side
logger.exception("Unhandled exception [error_id=%s]", error_id)
# Return only correlation ID to the client
return jsonify({
"error": "An unexpected error occurred",
"error_id": error_id
}), 500

Watch out for: logger.error("Failed to process: " + input, ex) - string-concatenating untrusted input into the log message can also violate 7.1.1 if input contains sensitive data. Pass input as a parameter and evaluate whether it should be logged at all.

Production flag: Frameworks like Express, Flask, and Django have debug/development modes that return detailed error pages. These are useful in development and dangerous in production. Verify that debug mode is disabled on production deployments - a common oversight that leads directly to 7.4.1 violations.

  • Returning exception.getMessage() to the client. Especially common in hand-rolled error handlers. Exception messages often contain SQL fragments, file paths, or serialized request data.

  • Default framework error pages in production. Django’s DEBUG=True, Flask’s debug mode, Express’s default 500 handler - all return stack traces when misconfigured in production.

  • HTTP response headers revealing stack details. Some frameworks set X-Powered-By, Server, or custom debug headers that disclose implementation details.

  • Logging exceptions with untrusted input interpolated. logger.error (f“Failed to process {user_input}”) can turn an error event into a PII exposure if user_input is sensitive.

  • Returning validation errors that echo invalid input. “Email ‘[email protected]’ is not valid” discloses the submitted value, which may be sensitive if the user mistyped into the wrong field.

HoundDog.ai’s scanner detects two specific patterns that map to 7.4.1:

  • CWE-209: Generation of Error Message Containing Sensitive Information. Reported on the Standard Output and Standard Error data sinks, flagging sensitive data written to the process output or error streams.

  • CWE-532 (overlap): Insertion of Sensitive Information into Log File. When 7.4.1 violations manifest as sensitive data written to error logs, the detection overlaps with 7.1.1 tooling.

The scanner runs as a CLI locally and in CI/CD pipelines (GitHub Actions, GitLab CI/CD, Azure Pipelines, CircleCI, Bitbucket Pipelines, Jenkins) to surface these issues during code review, before the code reaches production.

  • 7.4.2 - Codebase-wide exception handling. Exception handling (or a functional equivalent) must be used across the codebase to account for both expected and unexpected error conditions.

  • 7.4.3 - Last-resort error handling. A last-line-of-defense handler must exist to ensure no unhandled exception reaches the user.

  • 7.1.1 - Logging sensitive data. When errors are logged, 7.1.1 applies to ensure sensitive data doesn’t reach log files. Covered on our dedicated OWASP ASVS 7.1.1 page.

HoundDog.ai’s Privacy Code Scanner (hounddog scan) reports the code patterns behind ASVS 7.4.1 that involve sensitive data leaving through error output. The scanner reports CWE identifiers and OWASP Top 10 2021 categories on its findings, not ASVS requirement IDs (see OWASP ASVS Categories).

  • Sensitive data types. The scanner ships with over 100 data element definitions covering common PII, PHI, CHD, PIFI, and secret data (tags PII, PHI, CHD, PIFI, SECRET); the full list is in the scanner’s data-elements.md. A finding names the data element involved, such as Email or Social Security Number.

  • Sinks. Sensitive data reaching the Standard Output (stdout) and Standard Error (stderr) data sinks is reported as CWE-209. Sensitive data written to application logs, including error logs, is reported as CWE-532, which overlaps with ASVS 7.1.1.

  • Languages. Dataflows are reported for Python, JavaScript, TypeScript, Java, C#/.NET, and Go. Other supported languages are scanned for data elements only and produce no dataflows. See Supported Languages.

  • Sanitization. When AI dataflow reviews are enabled, each dataflow is reviewed with its code and trace in context, including any sanitization logic (masking, hashing, encryption, redaction) applied before the data reaches the sink. Dataflows where the data is effectively sanitized are marked as false positives.

For example, scanning a Python file that prints a user’s email address produces a finding like this (console output, excerpt; the file path is shortened):

print(f"Failed to process {user.email}")
🟨 LOW: Email sent to Standard Output in /path/to/project/app.py:2:5
2 │ print(f"Failed to process {user.email}")
Associated Compliance Frameworks
────────────────────────────────
CWE: CWE-1295, CWE-209
OWASP: A04:2021
Privacy: CCPA, GDPR-A5-32, NIST-800-53

To run a scan, see the quickstart. For how data elements and data sinks are defined and customized, see the scanner rules reference.