C and C++ programming are notorious for being bug-prone. Let’s look at the most dangerous software weaknesses in 2024 that are relevant for C and C++, so that you know what type of issues to test your code against in 2025.
We examined the 2024 CWE Top 25 Most Dangerous Software Weaknesses list developed by Common Weakness Enumeration (CWE™) and identified weaknesses relevant to C/C++. These weaknesses can become vulnerabilities. We explained how they occur and how you can uncover them.
1. Out-of-Bounds Write (CWE-787)
It’s a memory corruption issue that occurs when a program writes data outside the boundaries of allocated memory, potentially leading to arbitrary code execution or system crashes.
18 related CVEs (Common Vulnerabilities and Exposures) are actively exploited in the wild and listed in the Known Exploited Vulnerabilities (KEV) catalog.
Example of Out-of-Bounds Write:
#include <stdio.h>
#include <string.h>
int main() {
char buffer[10];
strcpy(buffer, "This string is too long!"); // Overwrites memory beyond buffer size
printf("%s\n", buffer);
return 0;
}
2. Out-of-Bounds Read (CWE-125)
It’s a memory corruption issue that happens when a program reads data beyond the allocated memory bounds, which can result in information disclosure or crashes.
3 related CVEs are actively exploited in the wild and listed in the Known Exploited Vulnerabilities (KEV) catalog.
Example of Out-of-Bounds Read:
#include <stdio.h>
int main() {
int arr[3] = {1, 2, 3};
printf("Out-of-bounds read: %d\n", arr[5]); // Reading beyond allocated memory
return 0;
}
3. Use After Free (CWE-416)
It’s a memory corruption issue that involves accessing memory after it has been freed, leading to undefined behavior, including potential code execution.
5 related CVEs are actively exploited in the wild and listed in the Known Exploited Vulnerabilities (KEV) catalog.
Example of Use After Free:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr = (int *)malloc(sizeof(int));
*ptr = 10;
free(ptr);
printf("Use after free: %d\n", *ptr); // Undefined behavior
return 0;
}
4. Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
It’s a memory corruption issue that encompasses various buffer overflow issues, where operations exceed buffer limits, causing unpredictable behavior.
2 related CVEs are actively exploited in the wild and listed in the Known Exploited Vulnerabilities (KEV) catalog.
Example of Improper Restriction of Operations within the Bounds of a Memory Buffer:
#include <stdio.h>
#include <string.h>
void vulnerable_function(char *input) {
char buffer[10];
strcpy(buffer, input); // No bounds checking
printf("%s\n", buffer);
}
int main() {
char large_input[] = "This string is way too long!";
vulnerable_function(large_input);
return 0;
}
5. NULL Pointer Dereference (CWE-476)
Occurs when a program attempts to use a null pointer, leading to crashes or denial of service.
Example of NULL Pointer Dereference:
#include <stdio.h>
int main() {
int *ptr = NULL;
printf("Dereferencing NULL: %d\n", *ptr); // Crash
return 0;
}
6. Integer Overflow or Wraparound (CWE-190)
Arises when arithmetic operations exceed the maximum value of an integer, causing unexpected behavior or vulnerabilities.
3 related CVEs are actively exploited in the wild and listed in the Known Exploited Vulnerabilities (KEV) catalog.
Example of Integer Overflow or Wraparound:
#include <stdio.h>
#include <limits.h>
int main() {
int max = INT_MAX;
int result = max + 1; // Integer overflow
printf("Integer Overflow: %d\n", result);
return 0;
}
How to Detect Vulnerabilities in C/C++
All these issues can be identified through white-box fuzz testing. Fuzz testing (or fuzzing) is an automated testing technique that feeds randomly generated, unexpected, or malformed inputs into a program to detect crashes and vulnerabilities.
Fuzzing helps uncover security flaws that traditional testing methods might miss, making it a crucial approach for securing C and C++ applications.
How White-Box Fuzz Testing Works:
- Identifying Targets – Fuzzing tools need to determine which critical functions or APIs execute a substantial amount of code and should be tested.
- Generating Fuzz Tests (Harnesses) – To interact with the identified targets, a fuzz test should be prepared for each target.
- Executing Tests with Random Inputs – Fuzzing tools run tests by feeding the application unexpected or malformed inputs to uncover potential flaws.
- Detecting Weaknesses – Flags potential vulnerabilities along with the specific line of code where the issue occurs, the stack trace, and the triggering input, enabling developers to fix the issue quickly.
Setting up a white-box fuzz testing tool to find the first vulnerabilities can require a lot of manual effort, but the good news is that these steps can be automated with the help of AI and LLMs. Learn more about how you can find bugs autonomously with AI-automated fuzz testing here.
Want to learn more about fuzz testing?
If you want to learn more about fuzzing and what types of fuzzing are there, check out this free “Fuzz Testing Solutions Comparison” guide. Inside, you’ll learn:
- The two main categories of fuzz testing and their key features.
- A detailed comparison of CI Fuzz—one of the market leaders—with white-box and protocol black-box fuzzers.