Back to Blog
critical SEVERITY10 min read

Heap Buffer Overflow in AX.25 Packet Parsing: How a Missing Bounds Check Could Let Attackers Hijack Your System

A critical heap buffer overflow vulnerability was discovered and patched in `src/ax25.c`, where a `memcpy` operation blindly trusted an attacker-controlled packet length field without validating it against the destination buffer's allocated size. This class of vulnerability is particularly dangerous because it allows remote attackers — anyone who can transmit an AX.25 packet over RF or a network feed — to corrupt heap memory, potentially leading to arbitrary code execution. The fix introduces pr

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

Answer Summary

This is a critical heap buffer overflow vulnerability (CWE-122) in C code that parses AX.25 radio packets in `src/ax25.c`. The root cause is a `memcpy` call that used an attacker-controlled packet length field without validating it against the destination buffer's allocated size, enabling remote code execution by anyone who can transmit a malformed AX.25 packet. The fix adds a bounds check that compares the packet's declared length against the actual allocated buffer size before performing the copy, rejecting any packet whose declared length exceeds the buffer capacity.

Vulnerability at a Glance

cweCWE-122
fixAdd a bounds check comparing the packet length field against the allocated buffer size before executing `memcpy`
riskRemote code execution by any attacker who can transmit an AX.25 packet over RF or network
languageC
root cause`memcpy` in `src/ax25.c` trusted an attacker-controlled packet length field without validating it against the destination heap buffer's size
vulnerabilityHeap Buffer Overflow

Severity: 🔴 Critical | CVE Class: Heap-Based Buffer Overflow (CWE-122) | Attack Vector: Remote (RF or Network)


Introduction

In the world of amateur radio and packet networking, the AX.25 protocol is a cornerstone — a link-layer protocol used by ham radio operators, satellite ground stations, and embedded communication systems worldwide. It's the kind of infrastructure that quietly hums in the background, often assumed to be safe because of its niche audience.

That assumption just got a reality check.

A critical heap buffer overflow vulnerability was identified and patched in src/ax25.c — the kind of bug that security researchers describe as a "write primitive," a foundational building block for full remote code execution. The root cause? A single memcpy call that trusted a number it should never have trusted: a length value supplied directly by the remote sender of an AX.25 packet.

If you write C or C++ code that parses network packets, reads binary data from external sources, or works with embedded protocol stacks, this post is required reading. The pattern is devastatingly common, and the consequences are severe.


The Vulnerability Explained

What Is AX.25?

AX.25 is a data link layer protocol derived from the X.25 standard, designed for use over amateur radio. An AX.25 packet contains several fields, including a variable-length information field — the payload of the packet. When software receives an AX.25 packet, it typically:

  1. Allocates a buffer to hold the information field.
  2. Reads the info_len field from the packet header to know how many bytes to copy.
  3. Uses memcpy (or equivalent) to copy the payload into the allocated buffer.

Step 3 is where things went wrong.

The Vulnerable Code Pattern

The vulnerability exists at src/ax25.c:208. Here's the conceptual pattern of what the vulnerable code looked like:

// Vulnerable pattern — DO NOT USE
int parse_ax25_packet(const uint8_t *raw_buf, size_t raw_len, ax25_frame_t *out) {

    // info_len is read DIRECTLY from the incoming packet
    out->info_len = read_uint16(raw_buf, OFFSET_INFO_LEN);

    // A buffer is allocated — but based on what size?
    // If the allocation uses a fixed size or a different calculation,
    // this is already dangerous.
    out->information = malloc(MAX_INFO_SIZE);
    if (!out->information) return -1;

    // ⚠️ CRITICAL: info_len comes from the attacker.
    // There is NO check that info_len <= MAX_INFO_SIZE.
    memcpy(out->information, raw_buf + OFFSET_INFO_DATA, out->info_len);
    //     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    //     If info_len > MAX_INFO_SIZE, this writes PAST the buffer!

    return 0;
}

The problem is elegant in its simplicity: the code allocates a buffer of a certain size, but copies a number of bytes controlled by the attacker. If the attacker sets info_len to a value larger than the allocated buffer, memcpy will happily write bytes beyond the end of the heap allocation.

Why Is This So Dangerous?

On the heap, memory allocations sit next to each other. When you overflow one allocation, you start overwriting the contents of adjacent allocations. In a modern heap layout, those adjacent regions might contain:

  • Heap metadata (chunk headers used by malloc/free) — corrupting these can cause free() to execute attacker-controlled code
  • Function pointers — overwriting a stored callback means the next time it's called, the attacker's code runs instead
  • Other data structures — credentials, session tokens, or configuration data
  • vtable pointers (in C++ code) — leading directly to virtual dispatch hijacking

This transforms a "simple" memory corruption into a potential remote code execution (RCE) primitive.

The Attack Scenario

Let's walk through a realistic attack:

[Attacker's Radio/Network Node]
        |
        |  Crafted AX.25 packet:
        |    info_len = 0xFFFF  (65535 bytes)
        |    actual payload = 512 bytes of shellcode + padding
        |
        v
[Vulnerable AX.25 Receiver]
        |
        |  malloc(512)  → allocates 512-byte heap buffer
        |  memcpy(..., 0xFFFF)  → writes 65535 bytes!
        |                          ^^^^^^^^^^^^^^^^^^^^^^
        |                          Overwrites adjacent heap chunks
        v
[Heap Corruption → Crash or Code Execution]

What makes this especially alarming:

  1. No authentication required. AX.25 operates at the link layer. Anyone within RF range — or connected to a network feed — can send packets. There's no login, no handshake, no credential check before the vulnerable code runs.

  2. The attack is remote. An attacker doesn't need physical access to the machine running this software. A malicious packet transmitted over radio or injected into a network APRS feed is sufficient.

  3. The attack is reliable. Heap overflows, especially with full control over the overflow size and content, are among the most exploitable memory corruption vulnerabilities. Modern exploit techniques like heap grooming can make these highly reliable even with ASLR enabled.


The Fix

What Changed

The fix introduces bounds validation before the memcpy call. The principle is straightforward: before copying N bytes into a buffer of size M, verify that N ≤ M. If the check fails, the packet is rejected as malformed.

Here's the corrected pattern:

// Fixed version — proper bounds checking
int parse_ax25_packet(const uint8_t *raw_buf, size_t raw_len, ax25_frame_t *out) {

    // Read info_len from the packet (still attacker-controlled)
    out->info_len = read_uint16(raw_buf, OFFSET_INFO_LEN);

    // ✅ FIX #1: Validate info_len against the maximum allowed size
    if (out->info_len > MAX_INFO_SIZE) {
        log_error("AX.25: info_len %u exceeds maximum %u, dropping packet",
                  out->info_len, MAX_INFO_SIZE);
        return -EINVAL;  // Reject the malformed packet
    }

    // ✅ FIX #2: Also validate against the actual raw buffer length
    // to prevent reading past the input buffer (a separate vulnerability)
    if (OFFSET_INFO_DATA + out->info_len > raw_len) {
        log_error("AX.25: packet truncated, dropping");
        return -EINVAL;
    }

    // Allocate exactly what we need (or use a pre-allocated buffer)
    out->information = malloc(out->info_len);
    if (!out->information) return -ENOMEM;

    // ✅ Now safe: we've verified info_len <= MAX_INFO_SIZE
    //              and the source data is within raw_buf bounds
    memcpy(out->information, raw_buf + OFFSET_INFO_DATA, out->info_len);

    return 0;
}

Key Security Improvements

Before After
info_len used directly without validation info_len checked against MAX_INFO_SIZE
No check against raw buffer bounds Validates info_len fits within raw_len
Attacker controls copy length Copy length bounded by constants
Heap overflow possible Malformed packets rejected before copy

The Two-Check Pattern

Notice that the fix includes two separate bounds checks, not one. This is intentional and important:

  1. Check against the destination buffer size — prevents heap overflow on write
  2. Check against the source buffer size — prevents heap over-read on read (a separate vulnerability that could leak memory contents)

Both checks are necessary. A fix that only adds one of them is incomplete.


Conclusion

A single missing bounds check in a memcpy call. That's all it takes to turn a packet parser into a remote code execution vulnerability. This isn't a theoretical concern — heap buffer overflows are regularly weaponized in real-world attacks, and AX.25 implementations are particularly exposed because they accept input from anyone within radio range, with no authentication barrier.

The fix is simple: validate before you copy. Check that the attacker-supplied length fits within your buffer. Check that it fits within the source data. Reject anything that doesn't comply. This three-line fix closes an attack surface that could have allowed a malicious actor to execute arbitrary code on any system running this software.

Key Takeaways

  • ✅ Never trust length fields from external input — always validate against known bounds
  • ✅ Apply two-sided bounds checks — validate against both source and destination sizes
  • ✅ Add ASan to your test suite — it catches these bugs immediately during development
  • ✅ Use static analysis in CI/CD — tools like CodeQL can find taint flows from network input to memcpy
  • ✅ Consider memory-safe languages for new protocol parser implementations
  • ✅ Treat all network-facing code as adversarial — assume the worst about every field in every packet

Security is not about perfection — it's about making exploitation as difficult as possible. Proper bounds checking is one of the most fundamental and effective defenses in the C programmer's toolkit. Use it, every time, without exception.


This vulnerability was identified and patched as part of an automated security review. If you maintain software that processes AX.25 packets or other binary protocols, audit your memcpy call sites today.

Fixed by OrbisAI Security — automated security analysis for modern codebases.

Prevention and further reading

Related Articles

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

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.

critical

Integer Overflow in edge_detect.c Heap Allocation Enables Camera-Based Exploit

A critical integer overflow vulnerability in `C/filters/edge_detect.c` allowed an attacker controlling a virtual V4L2 camera device to supply manipulated width/height dimensions that would silently wrap around to zero during multiplication, causing a drastically undersized heap allocation. Subsequent writes to this tiny buffer result in heap corruption, potentially enabling arbitrary code execution. The fix replaces the unsafe `malloc(w * h)` pattern with overflow-safe `calloc((size_t)w, (size_t

critical

Heap Corruption in Dynamic App Loaders: How Unvalidated Binary Size Fields Open the Door to Memory Attacks

A critical heap corruption vulnerability was discovered in a dynamic application loader where size values read directly from untrusted binary files were used to drive memory operations without any bounds validation. An attacker supplying a crafted app binary could overflow heap buffers, corrupt memory, and potentially achieve arbitrary code execution. The fix introduces strict bounds checks before memory operations and replaces unsafe allocation patterns with overflow-safe alternatives.

critical

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