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.
| 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 = -1or a new assignment (on the same line or after), or&xpassed to another function. - Releases in exclusive branches (
if/else,switchcases,#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
- Release each resource in exactly one place, typically the cleanup label.
- Set pointers to
NULLand descriptors to-1immediately after releasing them, and guard the cleanup withif (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.