Skip to content

VNX-1037: Processor Optimization Removal of Security-critical Code

Reports C and C++ secrets wiped with memset, bzero or ZeroMemory just before the memory is freed or goes out of scope, a dead store the optimizer may delete.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-1037
Severity Medium
SARIF level warning
Kind sast
Languages C, C++
CWE CWE-1037, CWE-14
CAPEC CAPEC-188
ATT&CK T1552
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 optimization memset volatile dead-store memory-zeroing cwe-1037
Source internal/sast/rules/vnx-cwe1037-auto.rego

Overview

VNX-1037 covers CWE-1037: Processor Optimization Removal or Modification of Security-critical Code. Processor-level removal (speculative execution) has no line-level signature, so this rule reports the concrete optimizer case: a compiler’s dead-store elimination of a buffer clear (CWE-14).

What is reported, in C and C++:

  • A zeroing call (memset/std::memset with fill value 0, '\0' or 0x00, bzero, ZeroMemory or RtlZeroMemory).
  • Whose buffer is named as a secret: key, password, passwd, passphrase, pwd, pin, otp, secret, seed, token, cred/credential, plaintext or master, including camelCase and prefixes such as szPassword or session_key.
  • Whose next statements, before any read of the buffer, free it (free, OPENSSL_free, g_free, kfree, HeapFree, LocalFree, delete …) or, for a local array, struct or std::array declared in the function, return or close its scope.

Not reported: explicit_bzero, memset_s, SecureZeroMemory, RtlSecureZeroMemory, OPENSSL_cleanse, sodium_memzero and other guaranteed wipes; a clear followed by a read of the buffer or by a compiler barrier that names it (initialisation, asm volatile); a clear of caller-owned memory (a pointer parameter or a struct member that outlives the function); buffers not named as secrets; non-zero fill patterns; test code, comments and strings.

Why This Matters

The C and C++ standards let a compiler delete a store that nothing reads afterwards. A memset(password, 0, sizeof password) right before free(password) or the end of the function is exactly such a store, and GCC, Clang and MSVC remove it at ordinary optimisation levels. The source code says the secret was wiped, but the binary leaves it in freed heap or on the stack, where a later allocation, a core dump, a swap file or a memory-disclosure bug can read it.

What Gets Flagged

char password[64];
read_password(password, sizeof password);
check(password);
memset(password, 0, sizeof(password));       /* FLAGGED: dead store before return */
return ok;
unsigned char derived_key[32];
pbkdf2(pin, derived_key, sizeof derived_key);
unlock_store(derived_key);
memset(derived_key, 0x00, sizeof derived_key);   /* FLAGGED: local array leaves scope */
}
std::memset(master_key.data(), 0, master_key.size());   // FLAGGED: std::array leaves scope
}

What Is Not Flagged

explicit_bzero(password, sizeof password);
OPENSSL_cleanse(key, key_len);
SecureZeroMemory(szPassword, sizeof szPassword);

Remediation

  1. Use a wipe the compiler must keep: explicit_bzero (glibc, BSD), memset_s (C11 Annex K), SecureZeroMemory/RtlSecureZeroMemory (Windows), OPENSSL_cleanse or sodium_memzero.
  2. In C++, wrap secrets in a type whose destructor calls one of those functions.
  3. If none is available, write through a volatile function pointer to memset, or follow the clear with a compiler barrier that names the buffer.

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

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

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