Skip to content

VNX-1341: Multiple Releases of Same Resource or Handle

Reports C/C++ code that releases the same pointer, descriptor or handle twice on one path (free, fclose, close, CloseHandle, delete, *_free/*_destroy/*_close/*_cleanup), including an error path that frees and then jumps with goto to a cleanup label that frees again. Releases followed by x = NULL, exclusive branches and early returns are not reported.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-1341
Severity Medium
SARIF level warning
Kind sast
Languages C, C++
CWE CWE-1341
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 double-release double-free memory-safety cwe-1341
Source internal/sast/rules/vnx-1341.rego

Overview

VNX-1341 maps to CWE-1341: Multiple Releases of Same Resource or Handle. Releasing the same memory, file, descriptor or library handle twice corrupts allocator state (double free), or closes a descriptor number that another thread has since reused.

Why This Matters

A double free is a classic memory-corruption primitive: an attacker who controls the allocations between the two frees can often turn it into arbitrary write and code execution. A double close() can close an unrelated file or socket opened in between.

What Gets Flagged

if (fread(buf, 1, 4096, f) == 0) {
    free(buf);                 // FLAGGED: then goto out, which frees buf again
    goto out;
}
...
out:
    free(buf);
if (expired) {
    free(s->token);
}
free(s->token);                // FLAGGED: second release when expired
delete entry_;
...
delete entry_;                 // FLAGGED

Release functions covered: free, fclose, close, closedir, pclose, closesocket, CloseHandle, kfree, vfree, g_free, munmap, delete/delete[], and library releasers named *_free, *_destroy, *_close, *_cleanup (EVP_CIPHER_CTX_free, sqlite3_close, curl_easy_cleanup).

What Is Not Flagged

  • A release followed by x = NULL, fd = -1 or a new assignment (on the same line or after), or &x passed to another function.
  • Releases in exclusive branches (if/else, switch cases, #if/#else).
  • An early release whose block returns, breaks or jumps to a label that does not release it again.
  • Loops releasing a different element each pass, releases in different functions, reference-count drops (*_unref, *_release) and comments.
  • Paths through other functions and aliases (q = p; free(p); free(q);) are not followed.

Remediation

  1. Release each resource in exactly one place, typically the cleanup label.
  2. Set pointers to NULL and descriptors to -1 immediately after releasing them, and guard the cleanup with if (p) / if (fd != -1).

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

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

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