CWE-122: Heap-Based Buffer Overflow — When Memory Corruption Escapes the Heap Boundary

cwe-122

Heap-based buffer overflows are among the most dangerous and technically complex memory corruption vulnerabilities in modern software. While stack overflows often target immediate control flow, heap overflows can corrupt long-lived objects, allocator metadata, adjacent allocations, and internal program state in ways that create subtle but powerful exploitation opportunities.

CWE-122 occurs when software writes beyond the bounds of a buffer allocated on the heap.

In practical terms:

The application overwrites dynamically allocated memory beyond its intended allocation.

This article breaks down how heap-based buffer overflows occur, why developers still introduce them, modern exploitation techniques, framework-specific mitigations, and secure coding patterns.

What Is a Heap-Based Buffer Overflow?

A heap-based buffer overflow happens when data written to a dynamically allocated memory region exceeds the size of that allocation.

Unsafe example:

char *buf = malloc(64);
memcpy(buf, userInput, userLen);

If userLen exceeds 64 bytes, the write extends beyond the heap allocation.

That overflow may corrupt:

  • Adjacent heap allocations
  • Object fields / pointers
  • Virtual table pointers
  • Heap allocator metadata
  • Free list / chunk metadata

How Heap-Based Buffer Overflow Actually Works

The core issue is writing more data than a heap allocation can contain.

Attack Flow

  1. Program allocates heap buffer
  2. Oversized data written into allocation
  3. Write exceeds heap chunk boundary
  4. Adjacent heap memory corrupted
  5. Application crashes or becomes exploitable

Visual: Heap Overflow Memory Layout

Heap Chunk A Heap Chunk B Overflow Corruption Write Extends Beyond Allocation

Why Developers Still Get Heap Overflows Wrong

Manual Memory Management

Developers must track allocation sizes manually.

Integer Miscalculation

Incorrect size calculations often allocate too little memory.

Dynamic / Variable-Length Data

Heap allocations frequently depend on attacker-controlled sizes.

False Confidence in Heap Allocators

Modern allocators include protections, but they do not prevent bugs.

Modern Exploitation Techniques

Adjacent Object Corruption

Overwrite neighboring object fields/pointers.

Virtual Table / Function Pointer Overwrite

Redirect control flow through corrupted pointers.

Heap Metadata Corruption

Manipulate allocator internals for arbitrary write primitives.

Tcache / Fastbin Poisoning

Modern allocator exploitation against glibc and similar allocators.

Use-After-Free Chaining

Heap overflow + stale pointer often creates stronger primitives.

Visual: Heap Overflow Exploitation Chain

Heap Overflow Adjacent Object Corruption Allocator Manipulation Pointer Overwrite RCE

How CWE-122 Differs from CWE-121 and CWE-787

CWE-121

Specifically:

Stack-based buffer overflow.

CWE-122

Specifically:

Heap-based buffer overflow.

CWE-787

Broader umbrella:

Any out-of-bounds write.

CWE-122 is a specialized subtype of CWE-787 focused on heap allocations.

Secure Coding Examples

Unsafe

char *buf = malloc(32);
strcpy(buf, input);

Safer

snprintf(buf, 32, "%s", input);

Better

std::vector<char> buf(input.begin(), input.end());

Prefer memory-safe abstractions when possible.

Framework / Language Mitigations

Hardened Allocators

Use allocator protections where available:

  • Heap cookies
  • Safe unlinking
  • Tcache hardening
  • Guard pages

Compiler / Runtime Defenses

Use:

  • ASLR
  • DEP/NX
  • CFI
  • AddressSanitizer

Memory-Safe Languages

Prefer when practical:

  • Rust
  • Go
  • Java
  • C#

Defense in Depth

Validate Allocation Sizes Carefully

Audit all attacker-influenced size calculations.

Check Copy Lengths Before Writes

Never assume caller-supplied lengths are safe.

Fuzz Heap-Manipulating Code

Heap bugs often surface under coverage-guided fuzzing.

Minimize Native Parsing Surface

Parser/decoder code frequently contains heap corruption bugs.

Final Thoughts

Heap-based buffer overflows remain dangerous because they corrupt one of the most complex and security-sensitive memory regions in a process.

They persist because:

  • Dynamic memory is difficult to reason about
  • Heap layouts are complex and non-deterministic
  • Modern allocators hide—but do not remove—risk
  • Exploit mitigations increase complexity, not safety

The core lesson is simple:

If untrusted input can overflow a heap allocation, attackers may reshape the program’s memory layout to their advantage.

Heap corruption is harder to exploit than it once was—but still highly exploitable when the right primitives exist.