Skip to content

VNX-170: Improper Null Termination

Reports C/C++ strncpy, memcpy(dst, src, strlen(src)) and read/readlink/recv/fread calls that can leave a buffer without a NUL terminator when nothing terminates it before it is used as a string.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-170
Severity High
SARIF level error
Kind sast
Languages C, C++
CWE CWE-170
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 null-termination memory cwe-170
Source internal/sast/rules/vnx-170.rego

Overview

VNX-170 maps to CWE-170: Improper Null Termination. It reports three shapes in C and C++ files:

  • strncpy(dst, src, n) with a count that can consume the whole buffer (sizeof dst, strlen(src), a variable or a constant) and no dst[...] = '\0' (or *p = '\0') within the next four lines. With n - 1 it is reported only when the buffer was not zeroed first (memset, bzero, = {0}, calloc, static storage).
  • memcpy(dst, src, strlen(src)), or memcpy(dst, src, len) with len = strlen(src) a few lines above and unchanged, which copies the characters but not the terminator, with no terminator after it.
  • read/readlink/recv/recvfrom/fread that fill a char array with sizeof(buf) bytes, after which the buffer is used as a string (strlen, strcmp, strstr, atoi/strtol, sscanf, printf("%s"), std::string, std::string s(buf), <<) within eight lines without buf[n] = '\0'.

Not reported: a string-literal source, a count of strlen(src) + 1, a length that is clamped before the copy or returned/stored with the bytes (a counted buffer, such as an OpenSSL password callback), an n - 1 strncpy whose last byte was terminated just before it, strlcpy/snprintf, a read of sizeof(buf) - 1, a buffer read as bytes only, strncpy wrapper functions, strncat (which always terminates), comments and string literals.

Why This Matters

strncpy does not write a terminator when the source is at least as long as the count, and read never writes one. The next strlen, printf("%s") or strcpy then runs past the end of the buffer, reading or copying adjacent memory: an information leak at best, an overflow at worst.

What Gets Flagged

// FLAGGED: no room for, and no write of, the terminator
strncpy(u->name, input, sizeof(u->name));

// FLAGGED: buffer filled completely, then parsed as a string
if (read(fd, buf, sizeof(buf)) < 0)
    return -1;
return atoi(buf);

// FLAGGED
memcpy(out, tok, strlen(tok));

// FLAGGED: readlink never terminates
ssize_t n = readlink("/proc/self/exe", target, sizeof(target));
printf("running %s\n", target);
// NOT FLAGGED: terminated
strncpy(dst, src, dstlen);
dst[dstlen - 1] = '\0';

// NOT FLAGGED: zeroed buffer, copy leaves the last byte
char local[40] = {0};
strncpy(local, src, sizeof(local) - 1);

Remediation

  1. Use strlcpy or snprintf(dst, size, "%s", src), which always terminate.
  2. After strncpy, write dst[size - 1] = '\0'.
  3. Read at most sizeof(buf) - 1 bytes and set buf[n] = '\0' with the returned count.

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

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

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