Skip to content

VNX-431: Missing Handler

Reports Java errors with no handler: a WEB-INF/web.xml with no error page for uncaught exceptions, and CompletableFuture.runAsync/supplyAsync or ExecutorService.submit whose future is discarded with no exception handler, so the task's exception is silently lost.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-431
Severity Low
SARIF level note
Kind sast
Languages Java
CWE CWE-431
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 missing-handler error-handling cwe-431
Source internal/sast/rules/vnx-431.rego

Overview

VNX-431 maps to CWE-431: Missing Handler. An error that something is expected to handle has no handler at all. In a servlet application, an uncaught exception then reaches the container’s default error page, which shows the stack trace and server version. In concurrent code, an exception thrown by a task whose future nobody keeps is captured in that future and never seen.

What Gets Flagged

  • A web.xml whose <web-app> has no <error-page> for java.lang.Throwable/Exception/RuntimeException, none for error code 500, and no default <error-page> with only a <location> (the <web-app> line is reported).
  • CompletableFuture.runAsync/supplyAsync used as a statement (future not assigned, returned or passed on) whose chain has no exceptionally, handle, whenComplete, join or get.
  • executor.submit(...) used as a statement, where executor is declared as an ExecutorService, ScheduledExecutorService, ThreadPoolExecutor or ForkJoinPool, or assigned from Executors.*.
CompletableFuture.runAsync(() -> store.save(r.rebuild()), pool);   // FLAGGED
workers.submit(() -> smtp.deliver(m));                             // FLAGGED

CompletableFuture.runAsync(task, pool).exceptionally(ex -> { log.error("failed", ex); return null; });  // not flagged
pool.execute(task);                                                // not flagged: reaches the uncaught-exception handler
<web-app ...>          <!-- FLAGGED when no error page covers uncaught exceptions -->
  <error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/error</location>
  </error-page>        <!-- with this, not flagged -->
</web-app>

Not reported: a task whose body catches Exception or Throwable, a kept future, execute(), test sources, comments. A broad @ExceptionHandler(Exception.class) is a handler and is not reported. The rule is evaluated only when the scanned tree also contains Java source, so a web.xml scanned alone, with no .java file beside it, is not read.

Remediation

  1. Declare <error-page> entries for java.lang.Throwable (and 500) pointing at a generic page.
  2. Keep the future and attach exceptionally/handle/whenComplete, or catch inside the task.
  3. Use execute() for fire-and-forget work so the thread’s uncaught-exception handler sees failures.

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

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

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