Back to Blog
critical SEVERITY8 min read

Heap Buffer Overflow in tzsp_forwarder.c: When Packets Attack

A critical heap buffer overflow vulnerability (CWE-120) was discovered and patched in `contrib/tzsp_forwarder.c`, where an attacker-controlled `caplen` value from a crafted network packet could overwrite adjacent heap memory structures. This class of vulnerability can lead to remote code execution, process crashes, or sensitive data disclosure. The fix introduces proper bounds validation before the dangerous `memcpy` operation, closing the door on this attack vector.

O
By orbisai0security
May 14, 2026

Heap Buffer Overflow in tzsp_forwarder.c: When Network Packets Attack Your Heap

Introduction

What if the data you were processing could secretly rewrite your program's memory? That's precisely what a heap buffer overflow allows — and it's one of the most dangerous vulnerability classes in systems programming. This week, a critical heap buffer overflow (CWE-120) was patched in contrib/tzsp_forwarder.c, a C component responsible for forwarding TZSP (TaZmen Sniffer Protocol) encapsulated network packets.

If you write C or C++ code that processes network data — or if you depend on software that does — this vulnerability and its fix are a masterclass in why never trusting attacker-controlled input is a foundational security principle.


Background: What is TZSP?

TZSP (TaZmen Sniffer Protocol) is a lightweight encapsulation protocol used to tunnel captured network packets from one device to another. It's commonly found in network monitoring equipment, wireless access points, and packet capture tools. A TZSP forwarder receives raw captured packets and re-encapsulates or relays them.

Because TZSP forwarders sit at the boundary between untrusted network data and internal processing logic, they are high-value targets for attackers. Any bug in how packet metadata is handled can have severe consequences.


The Vulnerability Explained

What Went Wrong

At line 53 of contrib/tzsp_forwarder.c, a memcpy operation copies data from a captured network packet into a destination buffer:

// VULNERABLE CODE (simplified)
memcpy(tzsp_packet + offset, captured_data, caplen);

The critical problem: caplen comes directly from the captured packet header — data that is entirely under the attacker's control. Before this fix, there was no validation to ensure that caplen bytes would actually fit into the remaining space of tzsp_packet (i.e., the allocated buffer size minus offset).

The Anatomy of the Attack

Here's what the vulnerable logic looked like conceptually:

// BEFORE: No bounds checking — DANGEROUS
uint8_t *tzsp_packet = malloc(TZSP_BUFFER_SIZE);
size_t offset = build_tzsp_header(tzsp_packet);  // some header bytes written

// caplen is read directly from the attacker-supplied packet header
uint32_t caplen = ntohl(pcap_header->caplen);

// If caplen > (TZSP_BUFFER_SIZE - offset), we overflow the heap!
memcpy(tzsp_packet + offset, packet_data, caplen);

An attacker crafts a malicious packet where the caplen field is set to a value larger than TZSP_BUFFER_SIZE - offset. When memcpy executes, it writes beyond the end of tzsp_packet, overwriting adjacent heap memory structures.

What Can an Attacker Actually Do?

Heap buffer overflows are notoriously powerful primitives for attackers. Depending on the heap layout and the target environment, exploitation can lead to:

Impact Description
Remote Code Execution (RCE) Overwriting heap metadata or function pointers to redirect execution flow
Process Crash / DoS Corrupting heap structures causes malloc/free to abort the process
Sensitive Data Disclosure Overwriting adjacent buffers containing credentials, keys, or private data
Privilege Escalation If the forwarder runs as root (common for raw socket access), RCE = full system compromise

Real-World Attack Scenario

Imagine a network monitoring appliance running this TZSP forwarder daemon with root privileges (required to open raw sockets). The appliance is connected to a mirrored switch port and receives all network traffic.

  1. Attacker sends a crafted UDP packet to the TZSP listener port with caplen set to 0xFFFFFFFF (4,294,967,295 bytes).
  2. The forwarder reads this value directly from the packet header without validation.
  3. memcpy begins writing ~4GB of data starting at tzsp_packet + offset.
  4. Within the first few kilobytes, it overwrites the metadata of adjacent heap chunks.
  5. On the next malloc or free call, the heap allocator reads corrupted metadata, potentially jumping to an attacker-controlled address.
  6. Game over — the attacker has code execution as root on the monitoring appliance, with visibility into all mirrored network traffic.

This isn't a theoretical scenario. CVE databases are full of real-world exploits following exactly this pattern.


The Fix

What Changed

The fix introduces bounds validation before the memcpy call. The corrected logic ensures that caplen cannot exceed the remaining available space in the destination buffer:

// AFTER: Bounds checking added — SAFE
uint8_t *tzsp_packet = malloc(TZSP_BUFFER_SIZE);
size_t offset = build_tzsp_header(tzsp_packet);

// caplen is read from the attacker-supplied packet header
uint32_t caplen = ntohl(pcap_header->caplen);

// Validate: ensure caplen fits within the remaining buffer space
if (caplen > TZSP_BUFFER_SIZE - offset) {
    // Log the anomaly and discard the malformed packet
    log_warning("Dropping packet: caplen %u exceeds buffer bounds", caplen);
    free(tzsp_packet);
    return;
}

// Now safe to copy
memcpy(tzsp_packet + offset, packet_data, caplen);

Why This Fix Works

The fix enforces a hard upper bound on caplen before it's used as the length argument to memcpy. No matter what value an attacker puts in the caplen field, the code will never write beyond the allocated buffer.

Key elements of a good fix here:

  1. Explicit upper bound check: caplen > TZSP_BUFFER_SIZE - offset catches the overflow condition. Note the subtraction order matters — subtracting offset from TZSP_BUFFER_SIZE (not the other way around) avoids an integer underflow if offset > TZSP_BUFFER_SIZE.

  2. Graceful rejection: Instead of truncating silently (which could cause other bugs), the malformed packet is logged and discarded. This also aids in detecting attack attempts.

  3. No silent truncation: A common mistake is to "fix" this by clamping: caplen = MIN(caplen, remaining). While this prevents the overflow, it silently processes a truncated packet, which may cause protocol-level issues downstream. Dropping the packet entirely is safer.

Integer Overflow Consideration

One subtle trap: if offset is larger than TZSP_BUFFER_SIZE (which shouldn't happen but could under other bugs), the subtraction TZSP_BUFFER_SIZE - offset wraps around to a huge number, making the check useless. A fully hardened version adds a secondary guard:

// Belt-and-suspenders: also guard against offset corruption
if (offset >= TZSP_BUFFER_SIZE || caplen > TZSP_BUFFER_SIZE - offset) {
    log_warning("Dropping packet: invalid offset or caplen");
    free(tzsp_packet);
    return;
}

Prevention & Best Practices

1. Never Trust Attacker-Controlled Length Fields

Any length, size, or count value that originates from network data, user input, or untrusted files must be validated before use in memory operations. This is the cardinal rule of safe C programming.

// ALWAYS validate before using external lengths
if (external_length > sizeof(buffer) - current_offset) {
    handle_error();
    return;
}
memcpy(buffer + current_offset, source, external_length);

2. Use Safe Memory Functions Where Available

Modern C libraries provide safer alternatives:

// Prefer memcpy_s (C11 Annex K) where available
errno_t err = memcpy_s(dest, dest_size, src, count);
if (err != 0) { /* handle error */ }

Or use wrappers that enforce bounds:

// OpenBSD-style: returns 0 on success, -1 on overflow
if (buf_append(&buf, src, caplen) < 0) {
    log_error("Buffer overflow prevented");
    return -1;
}

3. Leverage Compiler and OS Protections

These don't replace input validation but add layers of defense:

Protection How to Enable What It Catches
Stack Canaries -fstack-protector-strong Stack-based overflows
ASLR OS-level (default on modern Linux) Makes exploitation harder
FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 Detects some memcpy overflows at runtime
AddressSanitizer -fsanitize=address Detects heap overflows during testing
Valgrind Run during CI Memory error detection

Add these to your build pipeline:

CFLAGS += -Wall -Wextra -fstack-protector-strong -D_FORTIFY_SOURCE=2
# For testing/CI:
CFLAGS_TEST += -fsanitize=address,undefined

4. Fuzz Network Input Parsers

This vulnerability is exactly what fuzz testing is designed to find. Tools like AFL++ or libFuzzer can automatically generate malformed packets with extreme caplen values:

# Example: fuzz the TZSP parser with AFL++
afl-fuzz -i corpus/ -o findings/ -- ./tzsp_parser_harness @@

A good fuzzing harness for a packet parser would have found this bug immediately by generating a packet with caplen = UINT32_MAX.

5. Apply the Principle of Least Privilege

Even if this vulnerability were exploited, running the TZSP forwarder as a non-root user with only the CAP_NET_RAW capability (instead of full root) would limit the blast radius:

# Grant only the needed capability, not full root
setcap cap_net_raw+ep /usr/sbin/tzsp_forwarder

6. Static Analysis

Tools that could have caught this vulnerability:

  • Coverity / CodeQL: Taint analysis tracks attacker-controlled data to dangerous sinks like memcpy
  • Clang Static Analyzer: Detects some buffer overflow patterns
  • Flawfinder / rats: Flags dangerous C functions like memcpy for manual review
# Quick scan with flawfinder
flawfinder contrib/tzsp_forwarder.c

Security Standards & References

  • CWE-120: Buffer Copy without Checking Size of Input ("Classic Buffer Overflow") — https://cwe.mitre.org/data/definitions/120.html
  • CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer
  • OWASP: Input Validation Cheat Sheet — https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html
  • SEI CERT C Coding Standard: Rule ARR38-C — Guarantee that library functions do not form invalid pointers
  • SANS CWE Top 25: Buffer overflow vulnerabilities consistently rank in the top 5 most dangerous software weaknesses

Conclusion

This vulnerability is a textbook example of why input validation at trust boundaries is non-negotiable in systems programming. A single missing bounds check on an attacker-controlled caplen field turned a routine memcpy into a potential remote code execution primitive.

The key takeaways from this fix:

Validate all external length values before using them in memory operations

Fail loudly — log and discard malformed packets rather than silently truncating

Guard against integer arithmetic issues in bounds calculations

Layer your defenses — compiler flags, ASLR, and least privilege all reduce impact even if a bug slips through

Fuzz your parsers — automated fuzzing is highly effective at finding exactly this class of bug

Buffer overflows have been a top vulnerability class for over 30 years — since the Morris Worm in 1988. They're not going away as long as C and C++ are used for network-facing code. The tools and techniques to prevent them are well-understood; the challenge is consistently applying them.

Write the bounds check. Save the heap.


This vulnerability was identified and patched as part of an automated security review. Special thanks to the OrbisAI Security scanner for flagging this critical issue.

Found a security vulnerability? Practice responsible disclosure and report it to the project maintainers before going public.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #3976

Related Articles

critical

Heap Buffer Overflow in Audio Ring Buffer: How a Missing Bounds Check Could Crash Your App

A critical heap buffer overflow vulnerability was discovered in `audio_backend.c`, where the audio ring buffer's `memcpy` operations lacked bounds validation before writing PCM data. Without checking that incoming data sizes fell within the allocated buffer's capacity, a maliciously crafted audio file could corrupt adjacent heap memory, potentially enabling arbitrary code execution. The fix adds a concise pre-flight validation guard that rejects out-of-range write requests before any memory oper

critical

Heap Overflow in TOML Parser: How Integer Overflow Leads to Memory Corruption

A critical heap buffer overflow vulnerability was discovered and patched in the centitoml TOML parser, where missing integer overflow validation on a `MALLOC(len+1)` call could allow an attacker to trigger memory corruption via a crafted TOML configuration file. The vulnerability (CWE-190) is reachable through community-distributed mod or map files that the game loads from its `config/` directory, making it a realistic attack vector for remote code execution. A targeted one-line guard now preven

critical

Critical Integer Sign Bug in runtime_malloc(): How a Missing Check Enables Heap Corruption

A critical vulnerability in `runtime/zenith_runtime.c` allowed the `runtime_malloc()` function to accept negative size values, which when cast to an unsigned type could either trigger a massive failed allocation or produce a dangerously undersized buffer ripe for overflow. The fix adds a simple but essential guard clause that rejects non-positive sizes before they ever reach `malloc()`. Left unpatched, this class of bug can lead to heap metadata corruption, process crashes, or even arbitrary cod

critical

Heap Buffer Overflow in Path Normalization: How Two Unsafe memcpy Calls Almost Became a Critical Exploit

A critical heap buffer overflow vulnerability was discovered and patched in `src/aux.c`, where two `memcpy` calls in a path normalization function copied data into buffers without verifying sufficient capacity. An attacker capable of influencing the current working directory path — through deeply nested directories or crafted symlinks — could trigger heap corruption with potentially severe consequences. The fix introduces an integer overflow guard that ensures buffer allocation math cannot wrap

critical

Critical Buffer Overflow in iiod Parser: How a Missing Bounds Check Opened the Door to Remote Code Execution

A critical buffer overflow vulnerability was discovered in the `iiod` parser's `yy_input()` function, where an off-by-one bounds check allowed an oversized network input stream to overflow a fixed-size buffer, potentially overwriting adjacent stack or heap memory. Because this code path is reachable from the network without authentication, a remote attacker could exploit this flaw to achieve arbitrary code execution. The fix tightens the bounds enforcement and ensures the function returns the co

critical

Integer Overflow to Heap Buffer Overflow: How a Missing Size Check Almost Took Down an Embedded Web Server

A critical integer overflow vulnerability (CWE-190 → CWE-122) was discovered and fixed in an embedded ESP web server, where the HTTP Content-Length header value was cast to a signed integer and used directly in a `malloc()` call without proper size validation. On 32-bit systems, a crafted request with a maximum-sized Content-Length value could cause the allocation size to wrap to zero, allowing an attacker to overflow the heap with arbitrary data. The fix correctly validates the signed header va