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.
| 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++:
- Socket address read as the wrong family. A
struct sockaddr *orsockaddr_storagecast (C cast orreinterpret_cast) tosockaddr_in,sockaddr_in6,sockaddr_un,sockaddr_llorsockaddr_nlwhen nothing in the 20 lines above within the same function establishes the family (sa_family,ss_family,ai_family, anAF_*constant) and the cast is not the start of filling the structure (its*_familyassigned within the next 4 lines). - 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 ofDerivedaccording to the project’s class declarations (one or two levels), when no condition in the 8 lines above names the variable and nodynamic_cast/typeidtests 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
- Check
sa_family/ss_familybefore casting a socket address and handle each family separately. - Use
dynamic_castand test the result, or check the object’s kind first, before downcasting. - Prefer
std::variantandstd::visitto hand-rolled tagged hierarchies.
References
- CWE-843: Access of Resource Using Incompatible Type (‘Type Confusion’)
- SEI CERT EXP39-C: Do not access a variable through a pointer of an incompatible type
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.