Back to Blog
high SEVERITY7 min read

Buffer Overflow in Meshtastic: How One Missing Bounds Check Opens the Door to Remote Code Execution

A critical buffer overflow vulnerability was discovered in the Meshtastic firmware's radio packet handler, where an unchecked `memcpy` operation allowed any node on the mesh network to send a crafted packet with an oversized payload length field, potentially overwriting adjacent memory. Because Meshtastic mesh nodes communicate without authentication, this vulnerability was remotely exploitable by any attacker within radio range — or even further through mesh relay. The fix adds a simple but ess

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

Answer Summary

This is a buffer overflow vulnerability (CWE-120) in the Meshtastic firmware's C-based radio packet handler, where an unchecked `memcpy` operation trusted the attacker-controlled payload length field from incoming LoRa packets. Any unauthenticated node on the mesh — or one hop away via relay — could send a crafted packet to overwrite adjacent memory, potentially enabling remote code execution. The fix adds a bounds check that validates the incoming payload length against the maximum allowed buffer size before the `memcpy` executes, preventing out-of-bounds writes entirely.

Vulnerability at a Glance

cweCWE-120
fixAdd a bounds check comparing the packet's payload length against the maximum buffer size before memcpy executes
riskRemote code execution by any unauthenticated node within radio or mesh relay range
languageC (Embedded Firmware)
root causememcpy called with an attacker-controlled length field from an incoming radio packet, with no bounds validation
vulnerabilityBuffer Overflow via unchecked memcpy in radio packet handler

Buffer Overflow in Meshtastic: How One Missing Bounds Check Opens the Door to Remote Code Execution

Introduction

Mesh radio networks like Meshtastic are increasingly popular for off-grid, decentralized communication — used by hikers, emergency responders, preppers, and hobbyists worldwide. They're designed to work without internet infrastructure, relaying messages node-to-node over LoRa radio. That decentralized, open nature is a feature. But it also means any device within radio range can send packets to your node — including malicious ones.

This post breaks down a critical buffer overflow vulnerability discovered in meshtastic.cpp, explains how it could be exploited over the air, and walks through the fix. Whether you're an embedded developer, a security researcher, or just a Meshtastic user, this vulnerability is a reminder that trust boundaries matter even in hobbyist firmware.


The Vulnerability Explained

What Is a Buffer Overflow?

A buffer overflow occurs when a program writes more data into a fixed-size memory region than it was designed to hold. The excess data spills into adjacent memory, potentially overwriting other variables, control structures, or return addresses. In C and C++, this class of bug is responsible for some of the most severe exploits in computing history — from the Morris Worm in 1988 to modern IoT device compromises.

This vulnerability is classified as CWE-120: Buffer Copy without Checking Size of Input ("Classic Buffer Overflow").

Where Was the Bug?

In components/meshtastic/meshtastic.cpp, around line 449, the firmware handled incoming encrypted radio packets like this:

// VULNERABLE CODE (before fix)
memcpy(radio_buffer.payload, mp->encrypted.bytes, mp->encrypted.size);

Let's unpack what's happening here:

  • radio_buffer.payload is a fixed-size buffer allocated on the stack or heap.
  • mp->encrypted.bytes is the raw encrypted payload from an incoming radio packet.
  • mp->encrypted.size is the attacker-controlled length field from that same packet.

The problem? There is no check that mp->encrypted.size is actually smaller than sizeof(radio_buffer.payload).

If an attacker sends a packet with encrypted.size set to 0xFFFF (65,535 bytes), the firmware will dutifully copy up to 65,535 bytes from the incoming packet data into a buffer that might only be 256 bytes wide. Everything past that 256-byte boundary gets overwritten — and that memory belongs to something else.

The Trust Problem: No Authentication on the Mesh

What makes this particularly dangerous is the threat model of Meshtastic itself. Mesh nodes do not authenticate each other. Any device with a compatible radio can broadcast packets that will be received and processed by nearby nodes. There's no TLS handshake, no certificate validation, no "is this a trusted sender?" check before transmit_radio_packet() is called.

This means the attack surface is:

  • Any node within direct radio range (~2–15 km depending on terrain and antenna)
  • Any node reachable through mesh relay — potentially much farther, as Meshtastic packets are relayed hop-by-hop

What Could an Attacker Do?

Depending on the memory layout of the target device (typically an ESP32), a successful overflow could:

  1. Corrupt heap metadata, causing undefined behavior or a crash (Denial of Service)
  2. Overwrite adjacent stack variables, changing program logic
  3. Overwrite a return address or function pointer, leading to arbitrary code execution
  4. Brick the device by corrupting critical firmware state

In the worst case, an attacker within radio range — or connected through the mesh — could achieve remote code execution on your ESP32 node without any physical access and without any credentials.

A Concrete Attack Scenario

Imagine Alice is running a Meshtastic node at a remote campsite for emergency communication. Bob, a malicious actor, is parked 3 km away with a compatible LoRa radio and a laptop. Bob crafts a raw Meshtastic packet with:

encrypted.size = 0xFFFF  // 65535 bytes
encrypted.bytes = [carefully crafted payload]

Bob transmits this packet. Alice's node receives it, calls transmit_radio_packet(), and the vulnerable memcpy fires — copying 65,535 bytes into a small fixed buffer. Depending on what Bob put in those bytes, he may have just taken control of Alice's device.


The Fix

The fix is elegant in its simplicity. Before performing the memcpy, a bounds check was added:

Before (Vulnerable)

memcpy(radio_buffer.payload, mp->encrypted.bytes, mp->encrypted.size);

After (Fixed)

if (mp->encrypted.size > sizeof(radio_buffer.payload)) {
    ESP_LOGE(TAG, "Encrypted payload too large: %u > %u",
             mp->encrypted.size, sizeof(radio_buffer.payload));
    return false;
}
memcpy(radio_buffer.payload, mp->encrypted.bytes, mp->encrypted.size);

Why This Works

The fix does three important things:

  1. Validates the length before use: mp->encrypted.size is compared against the actual size of the destination buffer using sizeof(). This is a compile-time constant, so it will always reflect the true buffer size even if the code is refactored later.

  2. Fails safely: Instead of attempting the copy and corrupting memory, the function logs an error and returns false. The packet is silently dropped. No crash, no corruption, no exploitation.

  3. Provides observability: The ESP_LOGE call logs the oversized packet with the actual sizes, which is invaluable for debugging and for detecting active exploitation attempts in the field.

The Diff at a Glance

+  if (mp->encrypted.size > sizeof(radio_buffer.payload)) {
+    ESP_LOGE(TAG, "Encrypted payload too large: %u > %u",
+             mp->encrypted.size, sizeof(radio_buffer.payload));
+    return false;
+  }
   memcpy(radio_buffer.payload, mp->encrypted.bytes, mp->encrypted.size);

Four lines. That's all it took to close a critical remote code execution vector.


Prevention & Best Practices

This vulnerability follows a well-worn pattern. Here's how to avoid it in your own embedded C/C++ code:

1. Always Validate Lengths Before memcpy / strcpy / sprintf

Any time you copy data into a fixed-size buffer, ask: "Where does the length come from?" If it comes from user input, a network packet, or any external source — validate it first.

// Bad
memcpy(dest, src, untrusted_length);

// Good
if (untrusted_length > sizeof(dest)) {
    return ERROR_TOO_LARGE;
}
memcpy(dest, src, untrusted_length);

2. Prefer sizeof() Over Magic Numbers

Using sizeof(buffer) instead of a hardcoded constant ensures your bounds check stays correct if the buffer size changes during refactoring.

// Fragile — breaks if PAYLOAD_SIZE changes
if (len > 256) { ... }

// Robust — always correct
if (len > sizeof(radio_buffer.payload)) { ... }

3. Use Safer Alternatives Where Possible

In higher-level C++ code, prefer std::vector, std::string, or std::span over raw buffers. For C-style copies, consider:

  • memcpy_s() (bounds-checking variant, available in C11 Annex K)
  • std::copy with range checks
  • Custom wrapper functions that enforce size limits

4. Treat All Network Input as Hostile

In embedded networking code, every field in every packet is attacker-controlled. Length fields, type fields, flags — all of it. Apply the principle of "trust nothing from the network" consistently.

5. Enable Compiler and Runtime Protections

Modern compilers and runtimes offer mitigations that can reduce the impact of buffer overflows:

Protection How to Enable What It Does
Stack canaries -fstack-protector-all (GCC/Clang) Detects stack smashing at runtime
AddressSanitizer -fsanitize=address (debug builds) Catches out-of-bounds accesses
FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 Adds bounds checks to libc functions
Static analysis Clang-Tidy, Coverity, CodeQL Finds bugs before runtime

For ESP32/ESP-IDF projects specifically, enabling CONFIG_COMPILER_STACK_CHECK_MODE_STRONG in menuconfig adds stack overflow detection.

6. Fuzz Your Packet Parsers

Tools like AFL++ and libFuzzer can automatically generate malformed inputs to find buffer overflows before attackers do. If your firmware parses radio packets, fuzz the parser.

Security Standards & References

  • CWE-120: Buffer Copy without Checking Size of Input — https://cwe.mitre.org/data/definitions/120.html
  • OWASP: Buffer Overflow — https://owasp.org/www-community/vulnerabilities/Buffer_Overflow
  • SEI CERT C Coding Standard: ARR38-C — Guarantee that library functions do not form invalid pointers
  • MISRA C:2012: Rule 21.17 — Use of string handling functions

Conclusion

This vulnerability is a textbook example of why input validation is non-negotiable in networked embedded systems. A single missing bounds check turned a routine memcpy into a remote code execution vector exploitable by anyone with a LoRa radio.

The fix is four lines of code. The potential damage without it? Complete compromise of every vulnerable Meshtastic node within mesh reach.

Key takeaways:

  • Never trust length fields from external sources — always validate against your actual buffer size.
  • Fail safely — when validation fails, return an error and drop the input rather than proceeding with dangerous operations.
  • Log anomalies — oversized packets are a sign of either bugs or active attacks; make them visible.
  • The attack surface of mesh networks is wide — unauthenticated, multi-hop radio means your threat model must include remote, anonymous attackers.

Secure coding in embedded systems isn't glamorous, but it's essential. The next time you reach for memcpy, take two seconds to ask: "Did I check the length?" Your users — and their devices — will thank you.


This vulnerability was identified and fixed by OrbisAI Security. The fix has been verified by automated re-scan and LLM code review.

Frequently Asked Questions

What is a buffer overflow in embedded firmware?

A buffer overflow occurs when a program writes more data into a fixed-size memory buffer than it can hold, overwriting adjacent memory. In embedded firmware like Meshtastic, this can corrupt stack frames, function pointers, or other critical data structures, often leading to crashes or attacker-controlled code execution.

How do you prevent buffer overflow in C embedded code?

Always validate the length of any data before copying it into a fixed-size buffer. Use explicit bounds checks (e.g., `if (len > MAX_PAYLOAD_SIZE) return;`) before any `memcpy`, `strcpy`, or similar operation. Prefer safer alternatives like `memcpy_s` where available, and enable compiler protections like stack canaries (`-fstack-protector`).

What CWE is buffer overflow?

Buffer overflow is classified under CWE-120 (Buffer Copy without Checking Size of Input, also called "Classic Buffer Overflow"). Related identifiers include CWE-119 (Improper Restriction of Operations within the Bounds of a Memory Buffer) and CWE-122 (Heap-based Buffer Overflow).

Is input sanitization enough to prevent buffer overflow in C?

No. Sanitization alone is insufficient in C. You must explicitly check the size of incoming data against the destination buffer's capacity before any copy operation. Even if data appears "clean," an oversized length field can trigger a buffer overflow regardless of the content being copied.

Can static analysis detect buffer overflow in C firmware?

Yes. Static analysis tools like Semgrep, CodeQL, Coverity, and Clang's static analyzer can detect unchecked `memcpy` calls where the length parameter derives from external or user-controlled input. Orbis AppSec automatically detected this exact pattern in the Meshtastic firmware and generated the fix.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #2

Related Articles

high

How insecure string copy functions happen in C apputils.c and how to fix it

A high-severity buffer overflow vulnerability was discovered in `src/apps/common/apputils.c`, where `strncpy()` was used without guaranteed null-termination across four call sites — including the `sock_bind_to_device()` and `getdomainname()` functions. The fix replaces all unsafe `strncpy()` calls with `snprintf()`, which enforces both length bounds and automatic null-termination. Left unpatched, these flaws could allow an attacker to corrupt memory, crash the process, or potentially execute arb

critical

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

A critical integer overflow vulnerability was discovered in OpenCV's HAL filter implementation where multiplying image dimensions without overflow protection could allocate dangerously undersized buffers. An attacker supplying crafted image dimensions (e.g., 65536×65536) could trigger heap corruption through out-of-bounds writes. The fix promotes the calculation to 64-bit arithmetic with a single cast.

critical

How buffer overflow via strcpy() happens in C zlib and how to fix it

A critical buffer overflow vulnerability was discovered in `general/libzlib/gzlib.c` where multiple `strcpy()` and `strcat()` calls operated without bounds checking. An attacker controlling file paths or error messages could overflow destination buffers, potentially achieving arbitrary code execution. The fix replaces these unsafe string operations with bounded `memcpy()` calls that respect pre-calculated buffer lengths.

critical

How buffer overflow in rcdevice.c request parser happens in C and how to fix it

A critical buffer overflow vulnerability was discovered in `src/main/io/rcdevice.c` at line 489, where the RC device request parser wrote incoming data into a fixed-size buffer without validating against the hard-coded maximum capacity `RCDEVICE_PROTOCOL_MAX_DATA_SIZE`. An attacker controlling the device's I/O data stream could overflow the buffer by sending a payload longer than `expectedDataLength`, potentially achieving arbitrary code execution. The fix adds a second bounds check against the

critical

How buffer overflow via unchecked memcpy offset happens in C++ PCL point cloud parsing and how to fix it

A critical out-of-bounds read vulnerability was discovered in `pcpatch_pcl.cpp` where the `readFloat` lambda performed a `memcpy` operation using an untrusted offset value without validating buffer boundaries. An attacker could craft malicious PCD point cloud files with large offset values to read memory outside allocated buffers, potentially leaking sensitive data or causing crashes. The fix adds a bounds check ensuring `f->offset + sizeof(float)` stays within the row buffer before any memory c

critical

How buffer overflow in stb_image.h memcpy happens in C image parsing and how to fix it

A critical buffer overflow vulnerability was discovered in stb_image.h at line 4823, where a memcpy operation copied image data without validating buffer bounds. The multiplication of width (x) and channel count (img_n) could overflow or exceed allocated memory, allowing attackers to corrupt memory through malicious PNG files. The fix adds an explicit size_t cast to prevent integer overflow during the buffer size calculation.