Skip to content

VNX-822: Untrusted Pointer Dereference

A C/C++ pointer is built from data an attacker controls, so dereferencing it reads or writes an attacker-chosen address. Reported: (1) a cast to a pointer type (C-style, including function-pointer casts and (T *)(uintptr_t), or reinterpret_cast<T *>) applied directly to a text-to-integer conversion (strtoul, strtoull, strtol, strtoll, atoi, atol, atoll, std::stoul/stoull/stol/stoll/stoi); (2) the same cast, possibly through an integer cast ((T *)(uintptr_t)v) and including a dereferenced store (*(T *)v = x), applied to a variable assigned from such a conversion or filled by sscanf/fscanf/scanf (any conversion, such as %lx or SCNxPTR) in the ten lines above; (3) sscanf/fscanf/scanf reading a %p conversion; (4) a pointer read out of a buffer received from recv, recvfrom, read or fread in the 30 lines above through a pointer-to-pointer cast (*(T **)(buf + n)); (5) in a Linux ioctl handler (a function taking struct file * and unsigned long arg, the signature possibly spread over three lines), arg cast to a pointer type without __user, which dereferences a user-space address directly instead of copying it with copy_from_user. Not reported: integer conversions that stay integers, (void __user *)arg, an integer passed through a void * to pthread_create/thrd_create/g_idle_add-style callbacks, thread or callback arguments cast back to their context type, pointers to a validated table entry (&table[idx]), printf %p, and comments.

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

Overview

VNX-822 maps to CWE-822: Untrusted Pointer Dereference. It reports pointers made from numbers the caller supplies: parsed text, a packet, or a user-space ioctl argument.

What Gets Flagged

char *p = (char *)strtoul(argv[1], NULL, 16);               /* FLAGGED */
void (*fn)(void) = (void (*)(void))strtoull(argv[2], 0, 0); /* FLAGGED */

unsigned long addr = strtoul(optarg, NULL, 0);
int *target = (int *)addr;                                  /* FLAGGED: two-line form */

if (sscanf(line, "%p", &ptr) == 1) { ... }                 /* FLAGGED */

recv(sock, buf, sizeof(buf), 0);
struct node *next = *(struct node **)(buf + 8);            /* FLAGGED */

static long demo_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
	struct demo_req *r = (struct demo_req *)arg;          /* FLAGGED: no __user / copy_from_user */
auto *obj = reinterpret_cast<Widget *>(std::stoull(req.param("handle")));  // FLAGGED

Not flagged: unsigned long n = strtoul(s, NULL, 10); used as a number, copy_from_user(&req, (void __user *)arg, sizeof(req)), a thread argument cast back to its context struct.

/* FLAGGED: address parsed with sscanf, then dereferenced */
unsigned long addr;
sscanf(cmdline, "peek %lx", &addr);
uint32_t value = *(volatile uint32_t *)addr;

Not flagged: pthread_create(&t, NULL, worker, (void *)(intptr_t)id), the integer-in-a-pointer idiom for a thread argument.

Remediation

  1. Never turn external input into an address. Pass handles as indexes into a table the program owns, and validate the index.
  2. In kernel code, copy user data with copy_from_user/get_user through a __user pointer.
  3. Parse network data field by field into local values instead of reading pointers out of 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-822
// nosec vnx-822

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

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