Memory corruption vulnerabilities remain among the most devastating classes of software flaws, and CWE-787: Out-of-Bounds Write consistently ranks near the top of the SANS / MITRE Top 25 for one reason:
A single out-of-bounds write can turn a simple bug into full remote code execution.
Unlike many web vulnerabilities, memory corruption flaws often allow attackers to compromise the underlying process itself—overwriting adjacent memory, corrupting control flow, and executing arbitrary code.
This article breaks down how out-of-bounds writes occur, why they remain prevalent, how modern exploitation works, and what developers can do to prevent them.
What Is an Out-of-Bounds Write?
An out-of-bounds write occurs when software writes data outside the valid boundaries of an allocated memory buffer.
In practice:
The program places data into memory it does not own.
That overwritten memory may contain:
- Other variables
- Application state
- Heap metadata
- Function pointers
- Return addresses
- Security-critical control structures
How Out-of-Bounds Writes Actually Work
A buffer is allocated for a specific size:
char buffer[8];
If code writes more than 8 bytes:
strcpy(buffer, userInput);
and userInput contains 32 bytes, the extra data spills into adjacent memory.
Common Causes
1. Unsafe String Handling
char name[32];
strcpy(name, input);
No bounds checking.
2. Incorrect Length Validation
if (len <= 32)
memcpy(buf, src, len + 1);
Off-by-one errors remain common.
3. Integer Overflow Leading to Underallocation
size_t size = count * sizeof(Item);
malloc(size);
If multiplication overflows, the allocation is smaller than expected.
4. Improper Loop Bounds
for (int i = 0; i <= size; i++)
Using <= instead of <.
Why Developers Still Get It Wrong
Legacy Languages Prioritize Performance Over Safety
C and C++ provide raw memory access with minimal safety checks.
That flexibility enables performance—but places full responsibility on developers.
Unsafe APIs Persist
Dangerous functions remain widespread:
strcpystrcatsprintfgets- Unchecked
memcpy
Modern Complexity Increases Edge Cases
Even experienced developers struggle with:
- Variable-length inputs
- Nested allocations
- Serialization formats
- Protocol parsing
- Compression/decompression logic
Testing Rarely Covers Boundary Abuse
Typical tests validate expected behavior.
Attackers test:
- Maximum lengths
- Negative values
- Integer wraparound
- Malformed protocol fields
Modern Exploitation Techniques
Out-of-bounds writes are no longer exploited with simplistic “smash the stack” techniques alone.
Modern exploitation targets complex memory layouts.
Stack Buffer Overflow
Overwrites return addresses / saved registers.
Historically:
[ Buffer ][ Saved Frame Ptr ][ Return Address ]
Overflow modifies return address.
Heap Corruption
Attackers corrupt:
- Adjacent objects
- Heap metadata
- Virtual function tables
- Allocator bookkeeping
Function Pointer Overwrite
Overwrite callback pointers:
handler->callback = attacker_controlled_address;
Object Corruption / Type Confusion Chains
Particularly common in browsers:
- Corrupt object length fields
- Modify object type metadata
- Redirect execution indirectly
Visual: Exploitation Chain
Why This Vulnerability Is So Dangerous
Unlike many application flaws, out-of-bounds writes often result in:
- Remote Code Execution (RCE)
- Sandbox Escape
- Privilege Escalation
- Kernel Compromise
- Persistent Malware Installation
This is why memory corruption flaws dominate:
- Browser zero-days
- OS kernel exploits
- Hypervisor escapes
- Embedded device compromises
Secure Coding Examples
Unsafe
void copy_name(char *input) {
char buf[16];
strcpy(buf, input);
}
Safer Alternative
void copy_name(char *input) {
char buf[16];
strncpy(buf, input, sizeof(buf)-1);
buf[15] = '\0';
}
Note: strncpy is safer but still imperfect. Prefer modern safe abstractions where available.
Safer C++ Alternative
std::string name = input;
Use bounded abstractions instead of raw arrays.
Framework / Language Mitigations
Rust
Rust prevents most out-of-bounds writes by design:
let x = arr[10];
Triggers bounds checks / panic rather than silent corruption.
Modern C++
Prefer:
std::vectorstd::arraystd::spanstd::string
Over raw pointers / arrays.
Compiler Protections
Stack Canaries
Detect stack corruption before return.
ASLR (Address Space Layout Randomization)
Makes memory layout unpredictable.
DEP / NX
Prevents execution of injected shellcode from data pages.
Control Flow Integrity (CFI)
Restricts valid control flow transitions.
Important Reality Check
Mitigations reduce exploitability.
They do not eliminate the vulnerability.
Attackers routinely chain techniques to bypass:
- ASLR
- DEP
- Canaries
- Sandboxing
The only reliable fix is preventing the memory corruption.
Best Practices for Prevention
Validate All Lengths and Sizes
Treat all externally influenced lengths as untrusted.
Avoid Unsafe APIs
Ban dangerous functions in code review/tooling.
Use Memory-Safe Languages Where Possible
Prefer:
- Rust
- Go
- Java
- C#
for new development when performance constraints allow.
Fuzz Boundary Conditions
Fuzzing is particularly effective against memory corruption.
Test:
- Oversized inputs
- Malformed structures
- Edge-case lengths
- Nested malformed objects
Run Sanitizers in CI
Use:
- AddressSanitizer (ASan)
- UndefinedBehaviorSanitizer (UBSan)
- MemorySanitizer (MSan)
Final Thoughts
Out-of-bounds writes remain one of the most dangerous software weaknesses because they convert ordinary parsing or logic bugs into full system compromise.
They persist because:
- Unsafe languages remain widespread
- Legacy codebases are enormous
- Performance concerns discourage safety abstractions
- Developers underestimate boundary complexity
The lesson is straightforward:
If software manages memory manually, memory safety must be treated as a first-class security concern.

2 thoughts on “CWE-787: Out-of-Bounds Write — When Software Writes Beyond Its Limits”