VNX-415: Double free
Reports a C or C++ pointer released twice on one path: free/g_free/kfree/OPENSSL_free/delete of the same expression again within 20 lines with no reassignment, exit or branch in between, and a release followed by goto to cleanup code that releases it again. Nulled pointers, if/else and switch branches, other functions, macros and comments are not reported.
| Field | Value |
|---|---|
| Rule ID | VNX-415 |
| Severity | High |
| SARIF level | error |
| Kind | sast |
| Languages | C, C++ |
| CWE | CWE-415 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:H/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H |
| Tags | double-free memory-safety cwe-415 |
| Source | internal/sast/rules/vnx-415.rego |
Overview
VNX-415 maps to CWE-415: Double Free. Releasing the same heap block twice corrupts the allocator’s free lists; an attacker who controls the allocations in between can usually turn that into a write of their choosing.
The rule reports two shapes:
- A second release on the same path.
free,g_free,kfree,vfree,kvfree,OPENSSL_free,CRYPTO_free,xfree,std::free,deleteordelete[]of a variable or member expression, followed within 20 lines by another release of the same expression, with nothing in between that reassigns it (p = NULL,p = malloc(n),get(&p), reassigning the struct that holds the member), leaves the path (return,break,continue,goto,exit,abort,throwat the release’s nesting level) or starts another branch (else,case,default,#else, the end of the function). - Release, then goto cleanup. A release immediately followed by
goto LABEL, where the cleanup code underLABELreleases the same expression again without it having been nulled.
What Gets Flagged
free(buf);
if (rc != 0) {
log_error("invalid header");
}
free(buf); // FLAGGED: second release on the same path
if (token == NULL) {
free(name); // FLAGGED: the cleanup label frees name again
goto out;
}
...
out:
free(token);
free(name);
What Is Not Flagged
- A pointer set to
NULLor reassigned between the two releases. - Releases on the two arms of an
if/elseor in differentcases, and a release followed byreturn. - Releases in different functions,
#definemacros, string literals and comments. - Project-specific wrappers (other than
xfree) and aliases (q = p; free(p); free(q)), which are not tracked.
Remediation
Release each allocation in exactly one place, and set the pointer to NULL right after releasing it when other code may release it later:
free(name);
name = NULL;
goto out;
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-415
// nosec vnx-415
Or record an ignore rule: vulnetix ignore add --rule vnx-415 --reason "...". See Suppressing findings.