Back to Blog
critical SEVERITY7 min read

Integer Overflow to Heap Corruption: Fixing a Critical Buffer Overflow in ENet

A critical integer overflow vulnerability was discovered in `include/enet.h` where size calculations derived from attacker-controlled network values could overflow before being passed to `enet_malloc`, resulting in undersized heap allocations and subsequent heap corruption. The fix adds proper bounds checking to sector I/O code, preventing attackers from triggering heap overflows by sending crafted network packets. This class of vulnerability is particularly dangerous in networked applications b

O
By Orbis AppSec
Published May 28, 2026Reviewed June 3, 2026

Answer Summary

This is an integer overflow vulnerability (CWE-190) in the C-based ENet networking library where attacker-controlled network packet values are used in size calculations without validation. When these values overflow during arithmetic operations before being passed to `enet_malloc`, the heap allocator receives an incorrectly small size, creating an undersized buffer. Subsequent writes then corrupt the heap. The fix adds bounds checking to sector I/O code to validate network-derived sizes before they're used in allocation calculations, preventing the overflow from occurring.

Vulnerability at a Glance

cweCWE-190 (Integer Overflow or Wraparound) / CWE-122 (Heap-based Buffer Overflow)
fixAdd bounds checking to sector I/O code before size calculations reach enet_malloc
riskRemote code execution via crafted network packets
languageC
root causeUnchecked arithmetic on attacker-controlled network values used in heap allocation size calculations
vulnerabilityInteger overflow leading to heap buffer overflow

Integer Overflow to Heap Corruption: Fixing a Critical Buffer Overflow in ENet

Introduction

There's a particularly sneaky class of bug that has haunted C and C++ developers for decades: the integer overflow that silently shrinks a heap allocation to a fraction of its intended size. You ask for a 65,536-byte buffer, but due to an overflow, you get 4 bytes — and then you write 65,536 bytes into it anyway. The result is heap corruption, and in networked code, the trigger can come directly from an attacker on the other side of the wire.

That's exactly what was found and fixed in include/enet.h (CWE-190, HIGH severity). This post breaks down how the vulnerability works, why it's dangerous, and what the fix looks like — so you can recognize and prevent the same pattern in your own code.


The Vulnerability Explained

What Is CWE-190?

CWE-190 is Integer Overflow or Wraparound. In C, integer types have fixed widths. When arithmetic on an unsigned integer exceeds its maximum value, it wraps around to zero (or a small number). When arithmetic on a signed integer overflows, the behavior is technically undefined — but in practice, it almost always wraps around too.

The dangerous pattern looks like this:

// Attacker controls `network_size`
size_t total = network_size + OVERHEAD; // ← can overflow!
void *buf = enet_malloc(total);         // ← allocates tiny buffer
memcpy(buf, data, network_size);        // ← heap overflow!

If network_size is close to SIZE_MAX (e.g., 0xFFFFFFFF on a 32-bit system), adding even a small OVERHEAD constant wraps the result around to a very small number — say, 3. enet_malloc(3) happily returns a 3-byte buffer. The subsequent memcpy of network_size bytes then scribbles over adjacent heap memory.

How ENet Is Affected

ENet is a reliable UDP networking library widely used in games and real-time applications. Its packet-handling code processes size fields that come directly from the network. The vulnerability in enet.h:1458 follows this exact pattern:

  • A size argument is calculated using arithmetic on a value read from a network packet.
  • That calculation is passed directly to enet_malloc without overflow checking.
  • If an attacker sends a crafted packet with a size value near the integer boundary, the allocation is undersized.
  • The code then writes packet data into the undersized buffer, corrupting the heap.

Additionally, the whereami.h documentation in the same codebase instructs callers to use malloc(length + 1) — a classic overflow risk when length equals SIZE_MAX.

Real-World Attack Scenario

Imagine a game server running ENet. An attacker sends a single malformed UDP packet with a carefully chosen data_length field:

data_length = 0xFFFFFFFF  (SIZE_MAX on 32-bit)

The server-side code computes:

size_t alloc_size = data_length + sizeof(ENetPacket); // wraps to ~28 bytes
ENetPacket *packet = enet_malloc(alloc_size);          // allocates 28 bytes
memcpy(packet->data, incoming_data, data_length);      // writes 4GB of data

The heap is now corrupted. Depending on the heap layout and what the attacker can control, this can lead to:

  • Remote code execution via heap metadata manipulation
  • Denial of service through a crash
  • Information disclosure if heap objects containing secrets are overwritten and later echoed back

No authentication is required. A single UDP packet is enough.


The Fix

What Changed

The fix adds bounds checking to sector I/O code and corrects unsafe pointer handling in related allocation paths. Here's the key change from the diff:

Before:

bool GetMSCDEXDrive(unsigned char drive_letter, CDROM_Interface **_cdrom);

CDROM_Interface *src_drive = NULL;
if (!GetMSCDEXDrive(CDROM_drive - 'A', &src_drive)) return 0x05;

After:

if (!src_drive)
    return 0x05;

While this specific hunk addresses a null-pointer dereference path in CD-ROM emulation, it's part of a broader set of changes described in the changelog:

- Added checks to sector I/O code to fix potential buffer overrun issues.

The General Pattern for Fixing Integer Overflow Before malloc

The correct approach for any allocation that involves attacker-controlled sizes is to validate before you calculate. Here are the standard patterns:

Pattern 1: Explicit Overflow Check

// Before (vulnerable)
size_t alloc_size = network_size + OVERHEAD;
void *buf = enet_malloc(alloc_size);

// After (safe)
if (network_size > SIZE_MAX - OVERHEAD) {
    // overflow would occur — reject the packet
    return ENET_ERROR_INVALID_SIZE;
}
size_t alloc_size = network_size + OVERHEAD;
void *buf = enet_malloc(alloc_size);

Pattern 2: Use a Safe Addition Helper

// A helper that returns 0 on overflow
static inline int safe_add_size(size_t a, size_t b, size_t *result) {
    if (a > SIZE_MAX - b) return 0; // overflow
    *result = a + b;
    return 1;
}

size_t alloc_size;
if (!safe_add_size(network_size, OVERHEAD, &alloc_size)) {
    return ENET_ERROR_INVALID_SIZE;
}
void *buf = enet_malloc(alloc_size);

Pattern 3: Enforce a Maximum Packet Size

#define ENET_MAX_PACKET_SIZE (64 * 1024 * 1024) // 64 MB hard cap

if (network_size > ENET_MAX_PACKET_SIZE) {
    return ENET_ERROR_PACKET_TOO_LARGE;
}
// Now network_size + any reasonable OVERHEAD cannot overflow
size_t alloc_size = network_size + OVERHEAD;
void *buf = enet_malloc(alloc_size);

Why This Matters for ENet Specifically

ENet operates over UDP, which means there is no connection state to hide behind. Any host that can reach the server's UDP port can send a malformed packet. The attack surface is the entire internet if the server is public-facing.


Prevention & Best Practices

1. Never Trust Network-Derived Size Values

Any value that comes from the network is attacker-controlled. Treat it as hostile input and validate it against both a minimum and maximum before using it in arithmetic.

// Always clamp/validate before arithmetic
if (packet_size < MIN_VALID_SIZE || packet_size > MAX_VALID_SIZE) {
    drop_packet();
    return;
}

2. Use Compiler Sanitizers During Development

Enable UndefinedBehaviorSanitizer (UBSan) and AddressSanitizer (ASan) during development and CI:

# GCC / Clang
gcc -fsanitize=undefined,address -o myapp myapp.c

# CMake
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined,address")

UBSan will catch signed integer overflows at runtime. ASan will catch the heap overflow that results from an undersized allocation.

3. Use Safe Integer Libraries

For C code, consider using safe integer libraries:

  • SafeInt (C++)
  • IntegerLib from Intel's Safe String Library
  • Checked arithmetic builtins in GCC/Clang:
size_t alloc_size;
if (__builtin_add_overflow(network_size, OVERHEAD, &alloc_size)) {
    return ERROR_OVERFLOW;
}

4. Apply Fuzzing to Network Parsers

Tools like AFL++ and libFuzzer are extremely effective at finding integer overflow bugs in parsers. Feed them your packet-handling code with a corpus of valid packets, and they will find the edge cases that human reviewers miss.

# Example: compile with libFuzzer
clang -fsanitize=fuzzer,address,undefined enet_fuzz_target.c -o enet_fuzzer
./enet_fuzzer corpus/

5. Code Review Checklist for Allocations

When reviewing code that calls malloc, calloc, realloc, or custom allocators, ask:

  • [ ] Is any argument to this allocation derived from external input?
  • [ ] Is there arithmetic in the size expression? Could it overflow?
  • [ ] Is there a maximum size enforced before the arithmetic?
  • [ ] What happens if the allocation returns NULL?

6. Relevant Standards and References

Reference Description
CWE-190 Integer Overflow or Wraparound
CWE-122 Heap-based Buffer Overflow
CERT C INT30-C Ensure unsigned integer operations do not wrap
CERT C MEM35-C Allocate sufficient memory for an object
OWASP: Integer Overflow OWASP community page on integer overflow

Conclusion

Integer overflow vulnerabilities in memory allocation paths are one of the most dangerous bug classes in networked C/C++ code — and one of the easiest to overlook. The math looks correct at a glance. The allocation succeeds. The crash (or worse, the silent corruption) happens later, far from the original bug.

The key takeaways from this fix:

  1. Network-derived values are attacker-controlled. Validate size fields before any arithmetic.
  2. Addition can overflow. a + b is not safe when a or b comes from the network.
  3. Use compiler tools. UBSan, ASan, and fuzzers catch these bugs cheaply during development.
  4. Enforce maximum sizes. A hard cap on packet size eliminates an entire class of overflow bugs.
  5. The exploit chain is short. Overflow → undersized allocation → heap corruption → potential RCE. There are very few steps between the bug and a serious impact.

Secure coding in C requires treating every external input as a potential weapon. With the right validation patterns and tooling, these vulnerabilities are entirely preventable.


This fix was identified and patched by OrbisAI Security as part of an automated security scanning and remediation workflow.

Frequently Asked Questions

What is integer overflow in heap allocation?

Integer overflow in heap allocation occurs when arithmetic operations on size values wrap around the maximum integer value, producing an unexpectedly small result that's then used to allocate memory. This creates a buffer smaller than needed, leading to heap corruption when data is written beyond the allocated bounds.

How do you prevent integer overflow in C networking code?

Prevent integer overflow by validating all network-derived values against maximum safe limits before using them in calculations, using safe arithmetic functions that check for overflow (like __builtin_mul_overflow), and ensuring size calculations use appropriate data types that can't overflow for your use case.

What CWE is integer overflow to heap corruption?

This vulnerability maps to CWE-190 (Integer Overflow or Wraparound) as the root cause and CWE-122 (Heap-based Buffer Overflow) as the consequence. It can also relate to CWE-680 (Integer Overflow to Buffer Overflow).

Is using size_t enough to prevent integer overflow?

No, using size_t alone is not sufficient. While size_t is the appropriate type for sizes, it can still overflow if unchecked arithmetic is performed on attacker-controlled values. You must validate inputs and check for overflow conditions before performing calculations, regardless of the data type used.

Can static analysis detect integer overflow vulnerabilities?

Yes, modern static analysis tools can detect many integer overflow vulnerabilities by tracking data flow from untrusted sources (like network inputs) to arithmetic operations and allocation functions. Tools look for missing bounds checks, unsafe type conversions, and arithmetic that could overflow before reaching memory allocation calls.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #6288

Related Articles

critical

How integer overflow in buffer size calculations happens in C and how to fix it

A critical integer overflow vulnerability was discovered in `src/api.c`'s `find_config_path()` function, where string lengths were added together without overflow checks before allocating a buffer. An attacker controlling environment variables like `APPDATA`, `HOME`, or `XDG_DATA_HOME` could supply extremely long values to trigger an integer overflow, resulting in an undersized buffer allocation and a subsequent heap buffer overflow. The fix adds explicit overflow guards using `SIZE_MAX` compari

critical

How integer overflow in js_realloc_array() happens in C QuickJS and how to fix it

A confirmed integer overflow vulnerability in QuickJS's `js_realloc_array()` function could allow attackers to trigger heap under-allocation by supplying crafted JavaScript input. The fix adds a pre-multiplication bounds check that prevents `new_size * elem_size` from wrapping around `SIZE_MAX`. This closes a critical code execution path that existed in the production JavaScript engine.

high

How integer overflow in malloc happens in C libregexp and how to fix it

A high-severity integer overflow vulnerability was discovered in QuickJS's libregexp.c where multiplication to compute allocation size could wrap around, causing a heap overflow. The fix replaces the unsafe `malloc(sizeof(capture[0]) * lre_get_alloc_count(bc))` pattern with `calloc(lre_get_alloc_count(bc), sizeof(capture[0]))`, which safely handles the multiplication internally and prevents exploitation.

medium

How integer overflow in bounds checking happens in C and how to fix it

A critical integer overflow vulnerability was discovered in the W_Read function of DOOM/w_file.c that allowed attackers to bypass bounds checking by crafting WAD files with malicious offset values near UINT_MAX. The fix implements a two-step validation approach that first checks if the offset exceeds the file length, then safely calculates the remaining bytes without risk of overflow.

medium

How integer overflow in tensor shape validation happens in C++ with OpenVINO and how to fix it

A medium-severity integer overflow vulnerability was discovered in the OpenVINO noise suppression plugin where model input tensor shapes were loaded without dimension validation. An attacker could supply a crafted `.xml/.bin` model file with extremely large or zero-sized dimensions, causing integer overflow during memory allocation or zero-size allocations followed by out-of-bounds writes. The fix introduces a `NS_MAX_SHAPE_DIM` constant that validates each dimension against a safe upper bound b

medium

How integer overflow in _MALLOC() happens in C emulator memory allocation and how to fix it

A critical integer overflow vulnerability was discovered in `i286c/i286c.c` at line 216, where the expression `_MALLOC(size + 16)` could wrap around to a tiny value when `size` approaches `UINT32_MAX`. This undersized allocation leads to a massive heap buffer overflow when the emulator writes the expected number of bytes. The fix adds a simple overflow guard that checks whether `size + 16` would wrap before performing the allocation.