C and C++
Vulkro reads C and C++ source with a set of dedicated detectors and a short-range taint pass. It finds dangerous call shapes and proves a small set of input-to-sink flows. It is not a memory-safety verifier, and it reads no C or C++ package manager.
C and C++ are covered by vulkro (Core). Salesforce code is covered by the separate vulkro-sf binary.
vulkro scan .
vulkro scan . --all-confidence # also show the low-confidence leads
What is analysed
| Area | Coverage |
|---|---|
| Project detection | A .c / .h file or a Makefile, CMakeLists.txt, configure or *.mk (C); a C++ source or header file (C++) |
| Files read | C: .c, .h. C++: .cpp, .cc, .cxx, .c++, .hpp, .hh, .hxx, .h++, .ipp, .inl, .tcc. A .h file is read as C |
| Taint sources | argv, getenv, read / recv / fread / getline, fgets, the scanf family |
| Taint sinks | printf-family format strings, system / popen / exec*, a tainted length into memcpy / memmove / strncpy / strncat / bcopy with a fixed-size local array as the destination, file paths for fopen / open, allocation sizes |
| Taint range | Within one function, plus one call into a uniquely named project function |
| C++ | Every C detector and the taint pass also run on C++ files, plus six C++ rules |
| Endpoints and auth | Not analysed |
| Dependencies | None: no Conan, vcpkg or other C/C++ package manager is read |
Detectors
| Rule | What it finds | CWE |
|---|---|---|
C-BAN-001 | gets, strcpy, strcat, sprintf, vsprintf | 676 |
C-SCANF-001 | scanf %s / %[ with no field width | 120 |
C-FMT-001 | A non-literal printf-family format string | 134 |
C-CMDI-001, C-EXEC-001 | system / popen with a non-constant command; exec* launching a shell | 78 |
C-TLS-001 | TLS certificate verification turned off | 295 |
C-XXE-001 | libxml2 parsing with external entities enabled | 611 |
C-RAND-001 | rand for security values, predictable seeds | 338 |
C-TMP-001 | mktemp, tmpnam, tempnam | 377 |
C-PERM-001 | World-writable file or directory modes | 732 |
C-SETUID-001 | An unchecked setuid / setgid return | 252 |
C-ALLOC-001 | An unchecked multiplication in an allocation size | 190 |
C-STRNCPY-001 | strncpy / strncat that may leave no terminating null | 170 |
C-SIG-001 | A non-async-signal-safe call inside a signal handler | 364 |
C-CRED-001, C-KEY-001 | A secret compared with a literal; a hardcoded crypto key or IV | 798, 321 |
C-UAF-001, C-DF-001 | Use after free and double free in the same block | 416, 415 |
CPP-SMARTPTR-001, CPP-DANGLE-001 | delete of a smart pointer's .get(); returning the address of a local | 416, 562 |
CPP-MOVE-001, CPP-CAST-001 | Use of a moved-from object; reinterpret_cast | 825, 843 |
CPP-FMT-001, CPP-VCALL-001 | std::vformat / fmt::runtime format strings; a virtual call in a constructor or destructor | 134, 665 |
Hidden by default as low-confidence leads (shown with --all-confidence): C-MEM-001 (non-constant copy length), C-NULLDEREF-001 (unchecked malloc dereference), C-UNINIT-001 (uninitialized local read), C-TOCTOU-001 (check-then-use on a path) and C-ALLOCA-001 (runtime-sized stack allocation).
The taint pass reports under c-taint-format-string, c-taint-command, c-taint-buffer-overflow, c-taint-path and c-taint-alloc-size. Secrets, IaC and container checks run on a C or C++ repository as on any other.
Example
void log_message(void) {
char *msg = getenv("APP_MESSAGE");
printf(msg);
}
vulkro scan . reports an uncontrolled format string (CWE-134) on the printf line, with a trace from getenv to the sink. A finding with a trace is reported as proven.
Limits
- No memory-safety proof. There is no bounds, value-range or symbolic analysis. The use-after-free, double-free, null and uninitialized-read rules are same-block pattern checks, not proofs, and out-of-bounds access in general is not detected.
- Short range. Taint is followed inside one function, plus one call into a project function with a single definition. A path that crosses that call is demoted below the default confidence floor, and allocation sizes are not followed across it.
- No preprocessor. Source is parsed as written: a sink hidden behind a macro is not seen, and both sides of an
#if/#elseare read. - No C++ types. There is no type resolution, template instantiation or overload resolution, so lifetime bugs such as a dangling
string_vieware out of reach. There are no C++-specific taint sources (such asstd::cin). - No endpoint map, no auth model, no dependency CVEs.
See Supported languages for how C and C++ compare with the other languages.