Skip to content

VNX-209: Generation of Error Message Containing Sensitive Information

Detects stack traces and database error messages sent to the client: traces in Python, Java, JavaScript/TypeScript, Go and C# responses, PHP die/echo of mysqli_error and friends, caught database exception messages in Python, Java and C# output, and configuration that turns detailed error pages on (Spring include-stacktrace, PHP display_errors, ASP.NET customErrors Off).

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-209
Severity Medium
SARIF level warning
Kind sast
Languages Java, JavaScript / TypeScript, Python, PHP, Go, C#
CWE CWE-209
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C
Tags error-handling stack-trace information-exposure cwe-209
Source internal/sast/rules/vnx-209.rego

Overview

VNX-209 maps to CWE-209: Generation of Error Message Containing Sensitive Information. A stack trace tells an attacker the file layout, framework and library versions and the code path behind a failure; a database error message gives away SQL text, table and column names and the driver in use, which is exactly what is needed to shape an injection.

The rule reports the trace or message reaching the client, not its existence:

Language Reported
Python traceback.format_exc(), format_exception(), format_tb(), format_stack() passed to jsonify, make_response, HttpResponse, JsonResponse, JSONResponse, Response, render_template, abort, self.write (directly, or through a variable or dict assigned above); returned bare, or stored in an error dict that is returned, in a module that imports a web framework; traceback.print_exc(file=self.wfile); str(e) of a caught sqlite3.Error, psycopg2 error, DatabaseError, OperationalError, IntegrityError or SQLAlchemyError in a response
Java e.printStackTrace(response.getWriter()) or into a writer taken from the response where e is not the exception of the enclosing catch block (a parameter, a field); e.printStackTrace(new PrintWriter(sw)) then sw.toString() in a body or a controller return; ExceptionUtils.getStackTrace(e) in a return, body or writer; the getMessage() of a caught SQLException/DataAccessException/PSQLException/PersistenceException written to output or returned. A caught exception written to the servlet response from inside its catch block is reported by VNX-536, not here
JavaScript, TypeScript err.stack inside res.send/json/end/write/render (also a res / .status() / .json() chain split over lines), ctx.body or reply.send, also in a template literal, an object, or through a variable
PHP die/exit/echo/print of mysqli_error(), mysqli_connect_error(), mysql_error(), pg_last_error(), $db->error, $db->connect_error, getTraceAsString() or a caught PDOException message; ini_set('display_errors', 1); display_errors = On in php.ini/.htaccess
Go debug.Stack(), or the buffer filled by runtime.Stack(buf, ...), written to the http.ResponseWriter or a gin context
C# ex.StackTrace or ex.ToString() returned by Content/Ok/StatusCode/Problem or Response.Write; the Message of a caught SqlException/SQLiteException/DbException returned the same way or assigned to a WebForms control Text
Config Spring Boot server.error.include-stacktrace=always, include-exception=true; ASP.NET <customErrors mode="Off">, <httpErrors errorMode="Detailed">

What Gets Flagged

return jsonify({"error": "failed", "trace": traceback.format_exc()}), 500   # FLAGGED
except sqlite3.Error as exc:
    return jsonify({"error": str(exc)}), 500   # FLAGGED
res.status(500).send(err.stack);   // FLAGGED
n := runtime.Stack(buf, false)
w.Write(buf[:n])   // FLAGGED
return ResponseEntity.status(500).body(ExceptionUtils.getStackTrace(e));   // FLAGGED
} catch (SQLException sqle) {
    return failed(this).output(sqle.getMessage()).build();               // FLAGGED
$result = mysqli_query($conn, $query) or die('<pre>' . mysqli_error($conn) . '</pre>');   // FLAGGED
server.error.include-stacktrace=always   # FLAGGED

What Is Not Flagged

  • Traces and messages written to a logger, stderr, error_log() or console.error, with a generic message returned to the client.
  • traceback.print_exc() and e.printStackTrace() with no argument (they write to stderr).
  • Messages of exceptions other than database ones (IllegalArgumentException.getMessage(), lblError.Text = ex.Message on a generic Exception).
  • A trace returned from a helper in a module that imports no web framework (a crash file, a logging.Formatter.formatException).
  • A stack selected only outside production: stack: process.env.NODE_ENV === 'production' ? undefined : err.stack.
  • A trace or message that reaches the response through a helper function or another file.
  • A caught exception written to the servlet response inside its catch block (catch (Exception e) { e.printStackTrace(response.getWriter()); }, out.println(sqle.getMessage())): reported by VNX-536, the servlet form of this weakness.
  • display_errors set to 0/Off, include-stacktrace=never or on_param, customErrors mode="RemoteOnly".
  • The patterns in comments or string literals, and test code.

Remediation

Log the full error server-side and return a generic message with a correlation id.

except Exception:
    log.exception("order lookup failed", extra={"request_id": rid})
    return jsonify({"error": "internal error", "request_id": rid}), 500

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-209
// nosec vnx-209

Or record an ignore rule: vulnetix ignore add --rule vnx-209 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-209.rego, cli/internal/sast/docs/vnx-209.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.