CWE-562 is what happens when a function returns the address of one of its own local variables. The pointer looks fine to the caller. It is not.
MITRE puts it in C and C++. Anyone writing systems code, embedded firmware, parsers or native extensions can hit it. The usual outcome is a crash. In the worse cases an attacker can read or modify memory.
How it happens
Local variables live on the stack. When a function returns, its stack frame is invalidated. The memory is still there, but it now belongs to whatever function gets called next.
MITRE describes the effect directly. A subsequent function call is likely to reuse the same stack address, overwriting the value the pointer refers to. At best the value changes unexpectedly. In many cases the program crashes the next time the pointer is dereferenced.
Here is the classic shape:
// Vulnerable: returns the address of a local array
char *make_label(int id) {
char buf[32];
snprintf(buf, sizeof buf, "item-%d", id);
return buf; // buf is gone after this line
}
void show(void) {
char *a = make_label(1);
char *b = make_label(2); // reuses the same stack space
puts(a); // undefined behavior
}
The compiler will often warn about this. If your build suppresses warnings, or the pointer is passed through several layers, the bug survives.
It also hides in less obvious forms. Returning a pointer to a local struct member, storing the address of a local in a long lived object, or handing a stack pointer to a callback that runs later all have the same root cause.
The record lists one observed CVE: CVE-2024-33045, described as a product returning a stack variable address that leads to memory corruption. You can read more on the Gold page for CVE-2024-33045.
What an attacker gains
MITRE's consequences cover confidentiality, integrity and availability.
- Read memory. If the returned address is dereferenced after the return, an attacker may read data that now occupies that stack slot, such as other variables or buffers.
- Modify memory. If the pointer is written through, the write lands in someone else's data.
- Execute unauthorized code. Depending on how the address is used, corrupting stack contents can redirect control flow.
- Crash the process. The simplest and most reliable result is a denial of service.
Exploitability depends on what ends up in that stack slot and whether an attacker can influence it. Treat it as memory corruption, not as a harmless warning.
How to find it
MITRE lists three detection techniques.
- Fuzzing. Feeding large numbers of diverse inputs can trigger the crash or corruption. Pair it with sanitizers so the bug shows up as a clear error.
- Automated static analysis. SAST tools can find some instances. Compiler warnings are the cheapest first line. In GCC and Clang, look at the return of local address warnings and keep them as errors.
- Automated dynamic analysis. Use tools that insert runtime memory safety checks during compilation. AddressSanitizer with stack use after return detection is one example of this kind of tool.
Code review should also check every function that returns a pointer. Ask where the memory lives and who owns it.
How to fix it
MITRE's mitigation is to fix the code so that it does not return a stack address. In practice you have four options.
- Let the caller provide the buffer. The caller owns the memory, so its lifetime is clear.
- Allocate on the heap and document ownership. Return a
mallocpointer and make the caller free it. - Return by value. For small structs and scalars, copying is simple and safe.
- Use a static buffer only when single threaded and non reentrant. This is the weakest option. It breaks under concurrency.
// Fixed: caller supplies the buffer
int make_label(char *out, size_t cap, int id) {
int n = snprintf(out, cap, "item-%d", id);
return (n < 0 || (size_t)n >= cap) ? -1 : 0;
}
void show(void) {
char a[32], b[32];
make_label(a, sizeof a, 1);
make_label(b, sizeof b, 2);
puts(a);
puts(b);
}
For new code, consider whether C++ containers or a memory safe language fit the job. A std::string returned by value removes this entire class of mistake.
Native code also arrives through dependencies. If a package you use is affected by a memory bug like this one, you need to know whether your code reaches the vulnerable function. Reachability analysis answers that. To see what you depend on, the free scan at gold.safeguard.sh/scan runs in your browser with no login, keeps the file on your machine, and covers up to 100 dependencies.
Try it yourself
Click through it at your own pace, or open it full screen.
Quick check
Why does the returned pointer break?
The local variable lives in the function's stack frame, which is invalidated on return. The next function call can reuse that memory and overwrite the value.
Which languages does MITRE list?
C and C++.
What is the simplest safe fix?
Have the caller pass in the buffer, or return the value by copy, so no pointer to a dead stack frame escapes.