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
•Technically reviewed by Anupam Mediratta•Published May 28, 2026•Reviewed 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

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.


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.

Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #6288

Related Articles

high

nanoid 3.3.11 Integer Overflow: Predictable ID Generation

An integer overflow in nanoid 3.3.11's internal randomness generation causes the library to fall back to predictable ID sequences, undermining the cryptographic guarantees of its supposedly unguessable identifiers. The fix upgrades the dependency tree to patched versions 3.3.12 or 5.1.11.

medium

How Integer Overflow happens in C++ image processing and how to fix it

A signed integer overflow in OpenCV's `bilateralFilter.cpp` allowed the buffer size calculation `cal_width * cal_height * cn` to wrap around to a small or negative value, causing `padding.resize()` to allocate far less memory than needed. Subsequent `memcpy` operations would then write beyond the allocated buffer, creating a heap corruption primitive. The fix is a single targeted cast to `size_t` that promotes the multiplication to unsigned 64-bit arithmetic before any overflow can occur.

critical

How integer overflow in CsoundMYFLTArray constructor happens in C++ and how to fix it

A critical integer overflow vulnerability was discovered in `Java/cs_glue.cpp` at line 324, where the `CsoundMYFLTArray` constructor multiplied a user-controlled integer `n` by `sizeof(MYFLT)` without checking for overflow before passing the result to `malloc`. An attacker supplying a value near `INT_MAX` could trigger the overflow, causing an undersized heap allocation that subsequent writes would overflow. The fix adds an explicit `SIZE_MAX / sizeof(MYFLT)` guard and replaces `malloc` with `ca

high

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

A high-severity integer overflow vulnerability was discovered in the bipartite matching algorithm implementation where unchecked multiplication operations for memory allocation could wrap around, causing undersized buffer allocations and subsequent heap overflow. The fix replaces vulnerable `malloc(sizeof(int) * V)` patterns with safe `calloc(V, sizeof(int))` calls and adds proper bounds validation to prevent exploitation.

high

How integer truncation heap overflow happens in C++ UEFI ACPI parsing and how to fix it

A high-severity integer truncation vulnerability was discovered in `Mobility.Uefi.Acpi.cpp` where heap allocation sizes were stored in a 16-bit integer (`MO_UINT16`), causing silent truncation when the computed size exceeded 65535 bytes. This led to undersized heap allocations followed by out-of-bounds writes, exploitable by an attacker who can influence ACPI SRAT table contents in virtualized environments. The fix promotes the size variable to `MO_UINTN` (platform-native width) to prevent trunc

critical

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

A critical integer overflow vulnerability was discovered in the `nsh_setvar()` function in `nshlib/nsh_vars.c`, where the buffer size calculation `newsize = pstate->varsz + varlen` could wrap around, causing a heap buffer overflow. The fix adds overflow checking before the addition, preventing attackers with shell access from corrupting memory by setting variables with crafted names and values.