CWE-121 is the stack-based buffer overflow. MITRE defines it as a buffer overflow where the buffer being overwritten is allocated on the stack, which means it is a local variable or, more rarely, a parameter to a function. It is a variant of the classic overflow in CWE-120.
The affected platforms are memory-unsafe languages, C and C++ in particular. Anyone writing network services, parsers, embedded firmware or system tools in those languages should know this one well.
How it happens
When a function runs, its local variables sit on the stack next to bookkeeping data the program needs to continue. If you write past the end of a local array, you move through the neighboring memory. The code is never told that the data is too big, so it carries on.
// Vulnerable: fixed local buffer, unbounded copy
void parse_header(const char *line) {
char field[64];
strcpy(field, line); // line may be any length
handle(field);
}
If line comes from a network packet, a file or a command line, the sender chooses how many bytes get written. The bug looks harmless in testing because test inputs are short.
MITRE's observed example is CVE-2021-35395, stack-based buffer overflows in an SDK for a Wi-Fi chipset used in IoT and embedded devices. MITRE notes it was exploited in the wild per CISA KEV. That is a useful reminder of the supply chain angle: one vulnerable SDK ends up inside many devices from many vendors.
Other ways to hit this weakness include copying with a length taken from the input, off-by-one errors in loops, and string formatting into a fixed buffer. The shape is the same each time. A fixed local buffer meets data whose size the program did not control.
What an attacker gains
MITRE lists these consequences.
- Crashes and resource exhaustion. Overflows generally lead to crashes. They can also cause infinite loops, which consume CPU and memory.
- Code execution. Overflows can often be used to execute arbitrary code, outside the program's implicit security policy. The record lists modifying memory, executing unauthorized code or commands, and bypassing protection mechanisms.
- Subverting other defenses. When the result is arbitrary code execution, it can often be used to subvert any other security service, because the code now runs inside your trusted process.
On a router or an IoT device, that can mean a remote attacker taking over a box that sits inside someone's network.
How to find it
- Fuzzing. MITRE calls fuzzing a powerful technique for generating large numbers of diverse inputs, randomly or algorithmically, and running the code with them. Even limited fuzzing finds many shallow overflows.
- Static analysis. SAST tools can find some instances by analyzing source code or binaries without running them. Expect to confirm hits by hand.
- Runtime checks. Compile with AddressSanitizer for C and C++ to insert checks for memory safety errors. A stack overflow then aborts with a clear report.
A cheap first pass is to grep for fixed-size local arrays that are filled from a variable-length source. Each one needs a visible size check.
How to fix it
MITRE's record has no mitigation list, so the steps below come from the weakness definition and standard practice.
- Bound every write. Pass the destination size to the function that fills the buffer.
- Validate input length against the destination before copying, and reject oversized input.
- Use containers that know their own size, such as
std::stringandstd::vector. - Enable the compiler and platform hardening that your toolchain offers, and do not switch it off for performance without measuring. Hardening raises the cost of exploitation but does not fix the bug.
- Add ASan builds and fuzzing to CI so regressions are caught.
// Fixed: copy is bounded and oversized input is rejected
void parse_header(const char *line) {
char field[64];
if (strlen(line) >= sizeof field) {
return;
}
memcpy(field, line, strlen(line) + 1);
handle(field);
}
Check what you ship
If your product bundles a chip vendor SDK, a media library or a protocol stack, the overflow may not be in your code at all. Scan your dependency manifest with the free in-browser dependency scan. No login is needed, the file stays on your machine, and it handles up to 100 dependencies.
Quick check
What makes a stack overflow different from a heap overflow?
Only where the buffer lives. A stack overflow hits a local variable buffer, while a heap overflow hits memory from an allocator such as malloc. Both come from writing past the buffer's end. See CWE-122 for the heap case.
Do compiler protections remove the need to fix the code?
No. Protections make exploitation harder but the overflow still corrupts memory and can still crash the program. Fix the missing bounds check.