Skip to content

VNX-843: Access of Resource Using Incompatible Type ('Type Confusion')

A generic socket address is cast to a family-specific structure without checking its family, or a C++ base-class pointer or reference is downcast by static_cast, std::static_pointer_cast or a C cast without checking its dynamic type.

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

Overview

VNX-843 maps to CWE-843: Access of Resource Using Incompatible Type (‘Type Confusion’). It reports two shapes in C and C++:

  1. Socket address read as the wrong family. A struct sockaddr * or sockaddr_storage cast (C cast or reinterpret_cast) to sockaddr_in, sockaddr_in6, sockaddr_un, sockaddr_ll or sockaddr_nl when nothing in the 20 lines above within the same function establishes the family (sa_family, ss_family, ai_family, an AF_* constant) and the cast is not the start of filling the structure (its *_family assigned within the next 4 lines).
  2. Unchecked C++ downcast. static_cast<Derived *>/<Derived &> or a C-style (Derived *) cast of a variable whose declared type, in the 40 lines above, is a base class of Derived according to the project’s class declarations (one or two levels), when no condition in the 8 lines above names the variable and no dynamic_cast/typeid tests it.

Not reported: upcasts, casts inside a tagged dispatch (an if/switch on a type, kind or tag field in the 8 lines above), casts from void *, CRTP static_cast<Impl *>(this), numeric casts, reinterpret_cast to byte pointers, checked downcasts, unions and tagged-variant misuse, comments and string literals.

Why This Matters

A static_cast to the wrong derived class is undefined behaviour and the classic type-confusion exploit primitive: fields of one subclass are read and written through the layout of another. An IPv6 peer read as sockaddr_in, or a Unix socket path read as an IP address, reads memory through the wrong structure.

What Gets Flagged

double circle_area(Shape *s)
{
    Circle *c = static_cast<Circle *>(s);                     // FLAGGED
    return 3.14159 * c->radius * c->radius;
}

auto *in = reinterpret_cast<const sockaddr_in *>(addr);       // FLAGGED
void log_peer(const struct sockaddr *sa)
{
    const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;   // FLAGGED
}

Not flagged: a cast inside switch (sa->sa_family) { case AF_INET: ... }, if (s->kind() == 1) { ... static_cast<Circle *>(s) ... }, dynamic_cast<Circle *>(s), static_cast<Base *>(d).

Remediation

  1. Check sa_family/ss_family before casting a socket address and handle each family separately.
  2. Use dynamic_cast and test the result, or check the object’s kind first, before downcasting.
  3. Prefer std::variant and std::visit to hand-rolled tagged hierarchies.

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

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

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