CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-23833
1.70.12%

IoT Roulette: Analyzing the ESPHome Integer Overflow (CVE-2026-23833)

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 16, 2026·7 min read·6 visits

PoC Available

Executive Summary (TL;DR)

Integer overflow in ESPHome's protobuf decoder allows remote DoS via crafted packets. Fixed in version 2025.12.7.

A classic integer overflow vulnerability in the ESPHome API component allows unauthenticated remote attackers to trigger a Denial of Service (DoS) on ESP32, ESP8266, and RP2040 devices. By manipulating the length field of a Protobuf message, an attacker can bypass bounds checking, causing the device to attempt a read from invalid memory, resulting in a system crash and reboot.

The Hook: When Smart Homes Play Dumb

If you are into home automation, you know ESPHome. It is the firmware that turns cheap Chinese microcontrollers into obedient servants of your Home Assistant instance. It controls your lights, reads your temperature sensors, and manages your covers. It is the nervous system of the DIY smart home. But as we all know, embedded C++ is a minefield where one wrong move with a pointer blows your leg off.

CVE-2026-23833 is exactly that kind of mine. It resides in the api component—the high-speed, native protocol ESPHome uses to talk to Home Assistant (port 6053). Unlike MQTT, which parses text, the native API uses Protocol Buffers (protobuf). It's faster, lighter, and binary. It's also where the developers decided to implement their own decoding logic.

Now, writing a binary parser from scratch in C++ is a rite of passage for systems programmers. It is also usually where security goes to die. In this case, a fundamental misunderstanding of how computers add numbers allowed a remote attacker to force every smart switch in your house to commit seppuku simultaneously. No authentication required (if you aren't using encryption), just a single malicious packet.

The Flaw: A Math Lesson from Hell

To understand this bug, we have to talk about how computers handle memory and math, specifically on 32-bit architectures like the ESP32 and ESP8266. In C++, when you want to read a piece of data from a buffer, you typically have a pointer to your current position (ptr) and a pointer to the end of the buffer (end).

The vulnerability lies in how the decoder validates incoming fields. The code reads a field_length (a 32-bit unsigned integer) from the network packet. Before reading the data, it must check if the data actually fits in the remaining buffer. The developers wrote a check that looks intuitively correct to a human, but is disastrous to a compiler:

if (ptr + field_length > end) {
    return error;
}

Here is the catch: ptr is a memory address (essentially a 32-bit integer). field_length is also a 32-bit integer. If ptr is pointing to 0x3FF00000 (a valid heap address on ESP32) and the attacker says the field_length is 0xFFFFFFFF (4GB), the CPU performs the addition.

0x3FF00000 + 0xFFFFFFFF results in an Integer Overflow. The value wraps around zero, landing somewhere near 0x3FEFFFFF (depending on exact alignment). This wrapped-around value is numerically smaller than end. The check if (small_value > end) evaluates to false. The code thinks the check passed. The guard is asleep, and the barbarian is at the gate.

The Code: Anatomy of a Fix

The fix for this vulnerability is a textbook example of "safe coding practices 101" that often gets skipped in embedded development due to performance paranoia. The patch (Commit 69d7b6e) doesn't change the logic of what is being checked, but it changes the arithmetic used to check it.

Here is the side-by-side comparison of components/api/proto.cpp:

The Vulnerable Code

// The overflow happens right here in the addition
if (ptr + field_length > end) {
    this->error_code_ = ERROR_OUT_OF_BOUNDS;
    return false;
}

The Patched Code

// Safely calculate remaining space first
if (field_length > static_cast<size_t>(end - ptr)) {
    this->error_code_ = ERROR_OUT_OF_BOUNDS;
    return false;
}

Why this works: instead of asking "Does (start + length) go past end?", the fixed code asks "Is the length bigger than the space we have left (end - start)?".

Since end is guaranteed to be greater than or equal to ptr (assuming the loop hasn't already gone off the rails), end - ptr yields the legitimate remaining bytes. Comparing the untrusted field_length against this safe value prevents the overflow entirely. It is a subtle change, effectively just moving ptr to the other side of the inequality inequality algebra-style, but it makes the difference between a stable device and a brick.

The Exploit: Crashing the Party

Exploiting this is trivially easy if the API is exposed without encryption. The attacker connects to TCP port 6053 and initiates a Protobuf conversation. We don't even need to complete a handshake; we just need the parser to hit our malicious field.

The attack flow looks like this:

  1. Connect: Open a socket to 192.168.1.x:6053.
  2. Preamble: Send the initial 0x00 byte (signifying no encryption/preamble depending on version).
  3. Payload: Construct a Protobuf message. We specifically want a field with Wire Type 2 (Length Delimited).
    • The wire type is the lower 3 bits of the key.
    • We follow the key with a VarInt representing the length.
    • We set this length to 0xFFFFFFFF.

When the ESPHome device receives this, it calculates the new pointer position. Due to the overflow described above, the bounds check passes. The code then attempts to advance the pointer ptr += field_length.

Since field_length is huge, ptr now points to invalid memory (or wraps around to unmapped territory). The very next operation—trying to read from this location or parsing the next field from void*—triggers a LoadProhibited or StoreProhibited exception. The ESP32 panic handler catches this, dumps a backtrace to the serial console (which you won't see because you are remote), and reboots the device.

> [!NOTE] > While this is primarily a Denial of Service (DoS), on embedded systems without ASLR or memory protection, heap corruption can sometimes lead to RCE. However, given the nature of the crash (reading wild memory), reliable execution is unlikely. It's mostly just a nuisance.

The Impact: Why Low CVSS is Deceptive

The CVSS score for this is listed as 1.7 (Low), largely due to the AT:P (Attack Complexity/Requirements) vector. This assumes that most users have the native API encryption (Noise protocol) enabled. If encryption is on, the attacker needs the pre-shared key to even get the parser to look at the packet length.

However, many legacy setups or internal LANs run with encryption disabled for simplicity. In those environments, the score is functionally a 7.5 (High).

Imagine a scenario where an attacker gains access to your IoT VLAN. With a simple Python script, they can put every light switch, sensor, and thermostat into a boot loop. The devices will come up, accept a connection, receive the packet, crash, and repeat.

This isn't just about lights flickering. ESPHome is often used for critical triggers: turning on cooling fans for servers, managing aquarium heaters, or controlling garage doors. A persistent DoS on the controller means the logic stops running. The fish die, the server overheats, and the garage door stays open.

The Fix: Patching the Hole

The remediation is straightforward, but it requires flashing hardware, which is always a pain at scale.

1. Update Firmware

You need to update the ESPHome dashboard (or command line tool) to version 2025.12.7 or higher. Once updated, you must recompile and upload the firmware to every single device on your network. A dashboard update alone does nothing; the C++ code runs on the chip, not your server.

2. Enable Encryption (The Real Fix)

Even with the patch, parsing untrusted input is risky. The best mitigation is to ensure the parser never processes packets from strangers. Enable the encryption: key in your api: configuration:

api:
  encryption:
    key: "<generated_base64_key>"

This wraps the connection in the Noise protocol. Packets are authenticated before they are parsed. An attacker without the key cannot craft a valid frame, so the vulnerable integer addition code is never reached.

Official Patches

ESPHomePull Request merging the fix

Fix Analysis (1)

Technical Appendix

CVSS Score
1.7/ 10
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:U
EPSS Probability
0.12%
Top 69% most exploited

Affected Systems

ESPHome (API Component)ESP32ESP8266RP2040LibreTiny

Affected Versions Detail

Product
Affected Versions
Fixed Version
ESPHome
ESPHome
>= 2025.9.0, < 2025.12.72025.12.7
AttributeDetail
CWECWE-190 (Integer Overflow)
CVSS v4.01.7 (Low)
VectorCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L
Attack VectorNetwork (TCP/6053)
ImpactDenial of Service (Device Crash)
EPSS Score0.12% (0.00116)

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1190Exploit Public-Facing Application
Initial Access
CWE-190
Integer Overflow or Wraparound

The software performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value.

Known Exploits & Detection

Internal ResearchProof of concept involves sending a Length Delimited field with length 0xFFFFFFFF.

Vulnerability Timeline

Patch committed to main branch
2026-01-17
CVE-2026-23833 Published
2026-01-19
ESPHome 2025.12.7 Released
2026-01-19

References & Sources

  • [1]GitHub Advisory
  • [2]ESPHome API Documentation

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.