Back to Blog
critical SEVERITY9 min read

Heap Corruption via Integer Overflow in URI Parsing: A Deep Dive into CWE-190

A critical integer overflow vulnerability in `uri.c` allowed attackers to craft malicious URI strings that caused an undersized heap allocation followed by an out-of-bounds `memcpy`, leading to heap corruption. The fix adds mandatory bounds validation before any memory allocation, ensuring the `len + 1` calculation cannot silently wrap around to zero. Left unpatched, this vulnerability could enable remote code execution through carefully crafted URI inputs.

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published May 28, 2026•Reviewed June 3, 2026

Answer Summary

This is a CWE-190 integer overflow vulnerability in the C URI parser (`uri.c`). When `len` equals `SIZE_MAX`, the expression `len + 1` silently wraps to `0`, causing `malloc(0)` to return a tiny or NULL buffer followed by a full-length `memcpy` that corrupts the heap. The fix adds a pre-allocation guard — `if (len == SIZE_MAX) return NULL;` — that rejects any URI whose length would overflow a `size_t` before any memory is allocated or copied.

Vulnerability at a Glance

cweCWE-190
fixAdd `if (len == SIZE_MAX) return NULL;` guard before the allocation in `uri.c`
riskHeap corruption enabling remote code execution via crafted URI input
languageC
root cause`len + 1` wraps to 0 when `len == SIZE_MAX`, producing an undersized `malloc` followed by an oversized `memcpy`
vulnerabilityInteger Overflow leading to Heap Buffer Overflow

Introduction

Integer overflows are among the oldest and most dangerous classes of vulnerabilities in systems programming. They're subtle, they're silent, and when they occur in memory allocation paths, they can hand an attacker the keys to your process. This post examines a critical integer overflow vulnerability discovered and fixed in uri.c — a URI parsing component — that could allow a remote attacker to corrupt the heap and potentially achieve arbitrary code execution.

If you write C or C++, work with URI parsers, or simply care about memory safety, this one is worth understanding deeply.


The Vulnerability Explained

What Went Wrong

The vulnerable code pattern lives in uri.c around line 211–215. It looks something like this:

// VULNERABLE CODE — DO NOT USE
char *out = (char *) malloc(len + 1);
memcpy(out, range->first, len);

At first glance, this looks reasonable. Allocate len + 1 bytes (one extra for the null terminator), then copy len bytes in. Simple. Classic. Broken.

The problem is the len + 1 expression. In C, len is typically a size_t — an unsigned integer type. On a 64-bit system, size_t can hold values up to SIZE_MAX, which is 18446744073709551615 (2⁶⁴ - 1). If an attacker can supply a len value equal to SIZE_MAX, then:

SIZE_MAX + 1 = 0   (integer overflow — wraps to zero)

malloc(0) is implementation-defined but commonly returns a valid, non-NULL pointer to a zero-byte (or minimal) buffer. Then memcpy(out, range->first, SIZE_MAX) proceeds to copy an astronomically large number of bytes into that tiny buffer, obliterating the heap.

The Attack Path

This vulnerability is reachable via crafted URI input. The exploitation scenario follows this chain:

  1. Attacker submits a crafted URI — for example, through an HTTP request, a SQL query that embeds a URI, or any other input surface that feeds data into the URI parser.
  2. The parser extracts a range — the range->first pointer and a len value derived from pointer arithmetic on the URI string.
  3. len is attacker-influenced — if the URI is constructed such that the computed range length equals SIZE_MAX (or any value where len + 1 overflows), the overflow is triggered.
  4. malloc(0) returns a tiny buffer — the allocator happily hands back a pointer.
  5. memcpy writes far beyond the buffer — heap metadata, adjacent allocations, function pointers — all overwritten.

Real-World Impact

Heap corruption is not just a crash. A skilled attacker can:

  • Overwrite heap metadata to hijack allocator behavior on the next free() or malloc() call
  • Overwrite adjacent objects containing function pointers or vtable pointers
  • Chain with a second vulnerability (e.g., a use-after-free or type confusion) to achieve arbitrary code execution
  • Cause a denial of service at minimum — the process will almost certainly crash

This is classified as CWE-190: Integer Overflow or Wraparound, and it's rated CRITICAL for good reason.

Why URI Parsers Are High-Risk

URI parsers are a particularly dangerous place for this class of bug because:

  • They process untrusted, attacker-controlled input by design
  • They perform extensive pointer arithmetic on the input string to extract components (scheme, host, path, query, fragment)
  • The computed lengths are directly used in memory operations
  • They are often called early in request processing, before other validation layers

The Fix

What Changed

The fix adds explicit integer overflow checks before any memory allocation occurs. Here is the safe version:

// SAFE CODE — after the fix
static char *safe_uri_range_copy(const char *first, size_t len)
{
    /* Guard 1: len must not be SIZE_MAX — len+1 would overflow to 0 */
    if (len == SIZE_MAX) {
        return NULL;
    }

    /* Guard 2: belt-and-suspenders overflow check */
    if (len + 1 < len) {
        return NULL;
    }

    /* Guard 3: NULL pointer with nonzero length is invalid */
    if (first == NULL && len > 0) {
        return NULL;
    }

    /* Now it is safe to allocate */
    char *out = (char *) malloc(len + 1);
    if (out == NULL) {
        return NULL;  /* Guard 4: always check malloc return value */
    }

    if (len > 0) {
        memcpy(out, first, len);
    }
    out[len] = '\0';

    return out;
}

How Each Guard Works

Guard Condition Checked Why It Matters
Guard 1 len == SIZE_MAX Direct check for the exact overflow boundary
Guard 2 len + 1 < len Catches any overflow, even on unusual platforms
Guard 3 first == NULL && len > 0 Prevents NULL dereference in memcpy
Guard 4 out == NULL after malloc Prevents use of a failed allocation

Guards 1 and 2 are both present intentionally — this is a "belt and suspenders" approach. Guard 1 catches the most common case cleanly. Guard 2 is a portable, compiler-friendly overflow check that works even if SIZE_MAX is defined differently across platforms.

Before vs. After

// BEFORE: No validation — one crafted URI causes heap corruption
char *uri_range_to_string(uri_range_t *range) {
    size_t len = range->last - range->first;
    char *out = (char *) malloc(len + 1);  // ← overflow possible here
    memcpy(out, range->first, len);         // ← heap corruption here
    out[len] = '\0';
    return out;
}

// AFTER: Validation gates all memory operations
char *uri_range_to_string(uri_range_t *range) {
    size_t len = range->last - range->first;

    if (len == SIZE_MAX || len + 1 < len) {
        return NULL;  // ← reject overflow before it happens
    }

    char *out = (char *) malloc(len + 1);
    if (out == NULL) {
        return NULL;  // ← always check allocation
    }

    memcpy(out, range->first, len);
    out[len] = '\0';
    return out;
}

The change is small. The security improvement is enormous.


The Regression Test

The fix ships with a comprehensive regression test suite in tests/test_invariant_uri.c. This is worth highlighting because a fix without a test is an invitation for the bug to come back.

The test suite covers:

/* Test 1: Normal URIs — must parse correctly */
"http://example.com/path"
"https://user:pass@host:8080/path?query=val#frag"

/* Test 2: Adversarial — very long segments */
"http://aaaa...aaaa"  // 280+ 'a' characters

/* Test 3: Special characters and high bytes */
"http://evil.com/\xff\xfe\xfd\xfc"

/* Test 4: The exact overflow boundary */
safe_uri_range_copy(dummy, SIZE_MAX);  // Must return NULL

/* Test 5: NULL pointer with nonzero length */
safe_uri_range_copy(NULL, 10);  // Must return NULL

The key invariant the test enforces:

For any URI-like input, the length used in malloc must not overflow, and the allocated buffer must be large enough to hold len+1 bytes before any memcpy is performed.


Key Takeaways

The vulnerability fixed here is a textbook example of why input validation must happen before memory operations, not after. The fix is just a few lines of code, but those lines enforce a critical security invariant: the allocation size must always be large enough to hold the data being copied into it.

Here's what to take away from this fix:

  1. Integer overflow in malloc arguments is a heap corruption primitive — treat it as seriously as a direct buffer overflow.
  2. len + 1 is dangerous — always check that the addition doesn't overflow before passing the result to an allocator.
  3. URI parsers process attacker-controlled data — every length computed from URI input is a potential attack vector.
  4. Small fixes, big impact — four lines of validation eliminated a critical, potentially exploitable vulnerability.
  5. Tests make fixes permanent — the regression test ensures this vulnerability class cannot silently return in a future refactor.

Memory safety bugs don't announce themselves. They hide in arithmetic, waiting for the one input that makes the numbers lie. The defense is disciplined validation — check your sizes, check your pointers, and check your allocations. Every time.


This vulnerability was identified and fixed by automated security scanning. For more information on automated vulnerability detection and remediation, visit OrbisAI Security.

Prevention and further reading

Related Articles

critical

SGX Enclave ecall_store_data memcpy Buffer Overflow in 256-Byte

The Intel SGX enclave's trusted bridge functions `ecall_store_data` and `ecall_retrieve_data` used `memcpy()` to move data into and out of a fixed 256-byte `secure_storage` buffer without validating that `data_len` fit within destination boundaries. An attacker providing oversized `data_len` values could corrupt enclave memory, breaking SGX's confidentiality guarantees.

critical

How NULL pointer dereference from unchecked malloc() happens in C and how to fix it

A critical memory safety vulnerability was discovered in `bench/tokenizer/tokenizer.c` where `malloc()` was called without checking its return value before passing the pointer to `memcpy()`. If allocation fails and `malloc()` returns NULL, the subsequent `memcpy()` writes to address zero, causing heap corruption or potential arbitrary code execution. The fix adds a single NULL check immediately after allocation, exiting cleanly on failure rather than proceeding with a dangerously invalid pointer

critical

How Stack Buffer Overflows Happen in C with sprintf() and How to Fix Them

A critical stack buffer overflow was discovered in `libuv/Learn-libuv/docs/code/tty-gravity/main.c` where `sprintf()` wrote ANSI escape sequences and user-controlled variables into a fixed 500-byte buffer without any bounds checking. An attacker controlling the `pos`, `width`, or `message` variables could overflow the stack, overwrite return addresses, and potentially achieve arbitrary code execution. The fix replaces `sprintf()` with `snprintf()` and adds explicit length validation to ensure wr

high

How insecure string copy functions happen in C and how to fix them

A high-severity buffer overflow risk was discovered in `login/main.c` where `strcpy()` was used to copy the `HOME` environment variable into a fixed-size 512-byte buffer without any bounds checking. An attacker controlling the `HOME` environment variable could overflow `pwd_file_name`, potentially corrupting memory or hijacking execution. The fix replaces the two-step `strcpy`/`strcat` pattern with a single, bounds-safe `snprintf` call.

high

How c.lang.security.use-after-free.use-after-free happens in C and how to fix it

A use-after-free vulnerability was discovered in `ggml-alloc.c` where `galloc->leaf_allocs` could be referenced after being freed during graph memory reallocation. The fix nullifies the pointer immediately after `free()` and uses explicit `sizeof(struct leaf_alloc)` to prevent undefined behavior. This defensive hardening eliminates an exploit primitive in a speech-to-text processing pipeline.

critical

How buffer overflow in Intel SGX enclave ECALLs happens in C and how to fix it

A critical buffer overflow vulnerability was discovered in Intel SGX enclave functions `ecall_encrypt_data` and `ecall_decrypt_data` in `backend/sgx/enclave/enclave.c`. The functions performed memory operations without validating that the provided buffer lengths matched the actual allocated buffer sizes, allowing an attacker controlling the untrusted application to trigger heap corruption within the secure enclave by passing oversized length parameters.