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 calculations.c and how to fix it

A high-severity buffer overflow vulnerability was discovered in `src/calculations.c` at line 37, where a two-step `strncpy` + manual null-termination pattern left the door open for subtle memory safety bugs when copying string data into the `entry->type` field. The fix replaces both lines with a single `snprintf` call that handles bounds and null-termination atomically, eliminating the risk entirely. This is a common C pitfall that affects production CLI tools and can be exploited when attacker-

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.

high

How buffer overflow via sprintf() happens in C networking code and how to fix it

A high-severity buffer overflow vulnerability was discovered in `profile.c` where `sprintf()` was used to format server addresses without any bounds checking. An attacker who could influence the `SERVER_BASE_PORT` value or trigger integer overflow in the port calculation could write beyond the `server_address` buffer. The fix replaces `sprintf()` with `snprintf()` using explicit buffer size limits at both call sites (lines 99 and 220).

critical

How integer overflow happens in C reliable.c and how to fix it

A critical integer overflow vulnerability was discovered in `reliable.c` at line 1299, where the `packet_buffer_size` calculation used signed `int` arithmetic that could wrap to a negative or undersized value when large `fragment_size` values were involved. By casting each operand to `size_t` before multiplication, the fix eliminates the overflow risk entirely and ensures the allocated buffer is always large enough to hold the reassembled packet data.

high

How insecure string copy functions happen in C (cyw43.c) and how to fix it

Three unsafe string copy calls in `src/cyw43.c` — including a bare `strcpy()` and two `strncpy()` calls — created buffer overflow risks in a CYW43 Wi-Fi driver emulation layer. The fix replaces all three with `snprintf()`, which enforces buffer size limits and guarantees null-termination in a single, consistent operation. Left unaddressed, these vulnerabilities could allow an attacker controlling input like a TAP interface name or SSID to corrupt adjacent memory and potentially execute arbitrary