Skip to content

VNX-392: Missing Report of Error Condition

A Python web handler catches an exception and returns an error body (jsonify, JsonResponse, HttpResponse, Response, Sanic json or a dict) without an error status, so the client receives 200 OK for a failed request.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-392
Severity Low
SARIF level note
Kind sast
Languages Python
CWE CWE-392
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:L/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:L/DI:H/EX:L/EC:N/P:L
Tags error-handling cwe-392
Source internal/sast/rules/vnx-392.rego

Overview

VNX-392 maps to CWE-392: Missing Report of Error Condition. It reports, inside an except block, a return of jsonify(...), JsonResponse(...), JSONResponse(...), HttpResponse(...), Response(...) or make_response(...), or of a dict literal in a Flask, FastAPI, Django or Starlette module, whose content says the request failed (error, fail, invalid, not found, denied, unauthorized, forbidden, exception, missing, or the exception itself) and which sets no error status: no status=/status_code= argument and no (body, 4xx) tuple, or one that explicitly says 200 (status=200, (body, 200), HTTPStatus.OK). A call broken across lines is read as one statement.

Not reported: a response that sets a status, abort() or raise, a re-rendered HTML template (a form shown again with its error), a dict returned from a module that is not a web handler, test files, comments and strings.

Why This Matters

Clients, proxies, retries, monitoring and caches decide success by the status code, not by reading the body. An error answered with 200 is cached as a good response, never retried, never alerted on, and treated as success by any client that does not parse the body. Writing 'status': '500' into the JSON does not change what is sent on the wire.

What Gets Flagged

try:
    order.save()
except ValueError as e:
    return jsonify({"error": str(e)})                      # FLAGGED

except Cart.DoesNotExist:
    return JsonResponse({'message': 'failed', 'status': '500'})  # FLAGGED

Not flagged:

except ValueError as e:
    return jsonify(error=str(e)), 400
except OSError:
    return JsonResponse({"error": "storage unavailable"}, status=503)

Remediation

  1. Return the matching 4xx/5xx status with the error body: return jsonify(error=...), 400, JsonResponse(..., status=400).
  2. Or raise an HTTP exception (abort(404), HTTPException) and let the framework produce the response.

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-392
// nosec vnx-392

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

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