CVE-2026-45160
Description
An out-of-bounds read in ESP-IDF's DHCP server can lead to denial of service by crashing the DHCP server task.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
An out-of-bounds read in ESP-IDF's DHCP server can lead to denial of service by crashing the DHCP server task.
Vulnerability
An out-of-bounds read vulnerability exists in the DHCP server option parser (parse_options() in components/lwip/apps/dhcpserver/dhcpserver.c) within Espressif's ESP-IDF. Versions 5.2.7, 5.3.5, 5.4.4, 5.5.4, and 6.0.1 are affected. The parser does not validate option lengths against the packet buffer, allowing a crafted DHCP request to read past the buffer's end into adjacent heap memory. This affects devices acting as DHCP servers, such as those using ESP-IDF's SoftAP.
Exploitation
An unauthenticated attacker on the same Layer-2 network as the vulnerable device can send a single, crafted DHCP broadcast request. This request triggers the out-of-bounds read in the DHCP server's option parser. No prior association with the SoftAP is required, and any client connected to an open or PSK-protected SoftAP can initiate the exploit.
Impact
Successful exploitation results in a denial of service. The out-of-bounds read can crash the lwIP/DHCP server task or corrupt its state, preventing the server from assigning IP addresses to any clients on the SoftAP. The vulnerability does not leak data to the attacker; the read bytes are consumed as option metadata.
Mitigation
This issue has been patched in ESP-IDF versions 5.2.8, 5.3.6, 5.4.5, 5.5.5, and 6.0.2. The fix involves hardening the option parser to validate option bounds before processing, ensuring that option lengths and declared payload lengths do not exceed the buffer limits [1][2][3][4].
AI Insight generated on Jun 10, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
6fba5f995436afix(lwip): Fix DHCP servver OOB read issue
1 file changed · +33 −19
components/lwip/apps/dhcpserver/dhcpserver.c+33 −19 modified@@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,6 +49,7 @@ #define DHCPNAK 6 #define DHCPRELEASE 7 +#define DHCP_OPTION_PAD 0 #define DHCP_OPTION_SUBNET_MASK 1 #define DHCP_OPTION_HOST_NAME 12 #define DHCP_OPTION_ROUTER 3 @@ -917,7 +918,6 @@ static void send_ack(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) { ip4_addr_t client; - bool is_dhcp_parse_end = false; struct dhcps_state s; client.addr = *((uint32_t *) &dhcps->client_address); @@ -932,10 +932,31 @@ static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) DHCPS_LOG("dhcps: (s16_t)*optptr = %d\n", (s16_t)*optptr); #endif + if (*optptr == DHCP_OPTION_PAD) { + optptr++; + continue; + } + + if (*optptr == DHCP_OPTION_END) { + break; + } + + if (optptr + 1 >= end) { + break; + } + + u8_t opt_len = optptr[1]; + + if (optptr + 2 + opt_len > end) { + break; + } + switch ((s16_t) *optptr) { case DHCP_OPTION_MSG_TYPE: //53 - type = *(optptr + 2); + if (opt_len >= 1) { + type = optptr[2]; + } break; #if CONFIG_LWIP_DHCPS_REPORT_CLIENT_HOSTNAME @@ -966,31 +987,24 @@ static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) #endif case DHCP_OPTION_REQ_IPADDR://50 - if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { + if (opt_len >= 4) { + if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); #endif - s.state = DHCPS_STATE_ACK; - } else { + s.state = DHCPS_STATE_ACK; + } else { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); #endif - s.state = DHCPS_STATE_NAK; + s.state = DHCPS_STATE_NAK; + } } break; - - case DHCP_OPTION_END: { - is_dhcp_parse_end = true; - } - break; - } - - if (is_dhcp_parse_end) { - break; } - optptr += optptr[1] + 2; + optptr += opt_len + 2; } switch (type) {
8b4b5d530181fix(lwip): Fix DHCP servver OOB read issue
1 file changed · +33 −19
components/lwip/apps/dhcpserver/dhcpserver.c+33 −19 modified@@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,6 +49,7 @@ #define DHCPNAK 6 #define DHCPRELEASE 7 +#define DHCP_OPTION_PAD 0 #define DHCP_OPTION_SUBNET_MASK 1 #define DHCP_OPTION_HOST_NAME 12 #define DHCP_OPTION_ROUTER 3 @@ -917,7 +918,6 @@ static void send_ack(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) { ip4_addr_t client; - bool is_dhcp_parse_end = false; struct dhcps_state s; client.addr = *((uint32_t *) &dhcps->client_address); @@ -932,10 +932,31 @@ static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) DHCPS_LOG("dhcps: (s16_t)*optptr = %d\n", (s16_t)*optptr); #endif + if (*optptr == DHCP_OPTION_PAD) { + optptr++; + continue; + } + + if (*optptr == DHCP_OPTION_END) { + break; + } + + if (optptr + 1 >= end) { + break; + } + + u8_t opt_len = optptr[1]; + + if (optptr + 2 + opt_len > end) { + break; + } + switch ((s16_t) *optptr) { case DHCP_OPTION_MSG_TYPE: //53 - type = *(optptr + 2); + if (opt_len >= 1) { + type = optptr[2]; + } break; #if CONFIG_LWIP_DHCPS_REPORT_CLIENT_HOSTNAME @@ -966,31 +987,24 @@ static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) #endif case DHCP_OPTION_REQ_IPADDR://50 - if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { + if (opt_len >= 4) { + if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); #endif - s.state = DHCPS_STATE_ACK; - } else { + s.state = DHCPS_STATE_ACK; + } else { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); #endif - s.state = DHCPS_STATE_NAK; + s.state = DHCPS_STATE_NAK; + } } break; - - case DHCP_OPTION_END: { - is_dhcp_parse_end = true; - } - break; - } - - if (is_dhcp_parse_end) { - break; } - optptr += optptr[1] + 2; + optptr += opt_len + 2; } switch (type) {
2bf4dd12002dfix(lwip): Fix DHCP servver OOB read issue
1 file changed · +33 −19
components/lwip/apps/dhcpserver/dhcpserver.c+33 −19 modified@@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,6 +49,7 @@ #define DHCPNAK 6 #define DHCPRELEASE 7 +#define DHCP_OPTION_PAD 0 #define DHCP_OPTION_SUBNET_MASK 1 #define DHCP_OPTION_ROUTER 3 #define DHCP_OPTION_DNS_SERVER 6 @@ -902,7 +903,6 @@ static void send_ack(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) { ip4_addr_t client; - bool is_dhcp_parse_end = false; struct dhcps_state s; client.addr = *((uint32_t *) &dhcps->client_address); @@ -917,38 +917,52 @@ static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) DHCPS_LOG("dhcps: (s16_t)*optptr = %d\n", (s16_t)*optptr); #endif + if (*optptr == DHCP_OPTION_PAD) { + optptr++; + continue; + } + + if (*optptr == DHCP_OPTION_END) { + break; + } + + if (optptr + 1 >= end) { + break; + } + + u8_t opt_len = optptr[1]; + + if (optptr + 2 + opt_len > end) { + break; + } + switch ((s16_t) *optptr) { case DHCP_OPTION_MSG_TYPE: //53 - type = *(optptr + 2); + if (opt_len >= 1) { + type = optptr[2]; + } break; case DHCP_OPTION_REQ_IPADDR://50 - if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { + if (opt_len >= 4) { + if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); #endif - s.state = DHCPS_STATE_ACK; - } else { + s.state = DHCPS_STATE_ACK; + } else { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); #endif - s.state = DHCPS_STATE_NAK; + s.state = DHCPS_STATE_NAK; + } } break; - - case DHCP_OPTION_END: { - is_dhcp_parse_end = true; - } - break; - } - - if (is_dhcp_parse_end) { - break; } - optptr += optptr[1] + 2; + optptr += opt_len + 2; } switch (type) {
2da2db43fd7efix(lwip): Fix DHCP servver OOB read issue
1 file changed · +33 −19
components/lwip/apps/dhcpserver/dhcpserver.c+33 −19 modified@@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,6 +49,7 @@ #define DHCPNAK 6 #define DHCPRELEASE 7 +#define DHCP_OPTION_PAD 0 #define DHCP_OPTION_SUBNET_MASK 1 #define DHCP_OPTION_ROUTER 3 #define DHCP_OPTION_DNS_SERVER 6 @@ -879,7 +880,6 @@ static void send_ack(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) { ip4_addr_t client; - bool is_dhcp_parse_end = false; struct dhcps_state s; client.addr = *((uint32_t *) &dhcps->client_address); @@ -894,38 +894,52 @@ static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) DHCPS_LOG("dhcps: (s16_t)*optptr = %d\n", (s16_t)*optptr); #endif + if (*optptr == DHCP_OPTION_PAD) { + optptr++; + continue; + } + + if (*optptr == DHCP_OPTION_END) { + break; + } + + if (optptr + 1 >= end) { + break; + } + + u8_t opt_len = optptr[1]; + + if (optptr + 2 + opt_len > end) { + break; + } + switch ((s16_t) *optptr) { case DHCP_OPTION_MSG_TYPE: //53 - type = *(optptr + 2); + if (opt_len >= 1) { + type = optptr[2]; + } break; case DHCP_OPTION_REQ_IPADDR://50 - if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { + if (opt_len >= 4) { + if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); #endif - s.state = DHCPS_STATE_ACK; - } else { + s.state = DHCPS_STATE_ACK; + } else { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); #endif - s.state = DHCPS_STATE_NAK; + s.state = DHCPS_STATE_NAK; + } } break; - - case DHCP_OPTION_END: { - is_dhcp_parse_end = true; - } - break; - } - - if (is_dhcp_parse_end) { - break; } - optptr += optptr[1] + 2; + optptr += opt_len + 2; } switch (type) {
9f713dbc9498fix(lwip): Fix DHCP servver OOB read issue
1 file changed · +33 −19
components/lwip/apps/dhcpserver/dhcpserver.c+33 −19 modified@@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,6 +49,7 @@ #define DHCPNAK 6 #define DHCPRELEASE 7 +#define DHCP_OPTION_PAD 0 #define DHCP_OPTION_SUBNET_MASK 1 #define DHCP_OPTION_ROUTER 3 #define DHCP_OPTION_DNS_SERVER 6 @@ -879,7 +880,6 @@ static void send_ack(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) { ip4_addr_t client; - bool is_dhcp_parse_end = false; struct dhcps_state s; client.addr = *((uint32_t *) &dhcps->client_address); @@ -894,38 +894,52 @@ static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) DHCPS_LOG("dhcps: (s16_t)*optptr = %d\n", (s16_t)*optptr); #endif + if (*optptr == DHCP_OPTION_PAD) { + optptr++; + continue; + } + + if (*optptr == DHCP_OPTION_END) { + break; + } + + if (optptr + 1 >= end) { + break; + } + + u8_t opt_len = optptr[1]; + + if (optptr + 2 + opt_len > end) { + break; + } + switch ((s16_t) *optptr) { case DHCP_OPTION_MSG_TYPE: //53 - type = *(optptr + 2); + if (opt_len >= 1) { + type = optptr[2]; + } break; case DHCP_OPTION_REQ_IPADDR://50 - if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { + if (opt_len >= 4) { + if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); #endif - s.state = DHCPS_STATE_ACK; - } else { + s.state = DHCPS_STATE_ACK; + } else { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); #endif - s.state = DHCPS_STATE_NAK; + s.state = DHCPS_STATE_NAK; + } } break; - - case DHCP_OPTION_END: { - is_dhcp_parse_end = true; - } - break; - } - - if (is_dhcp_parse_end) { - break; } - optptr += optptr[1] + 2; + optptr += opt_len + 2; } switch (type) {
d51b10760924fix(lwip): Fix DHCP servver OOB read issue
1 file changed · +33 −19
components/lwip/apps/dhcpserver/dhcpserver.c+33 −19 modified@@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,6 +49,7 @@ #define DHCPNAK 6 #define DHCPRELEASE 7 +#define DHCP_OPTION_PAD 0 #define DHCP_OPTION_SUBNET_MASK 1 #define DHCP_OPTION_ROUTER 3 #define DHCP_OPTION_DNS_SERVER 6 @@ -902,7 +903,6 @@ static void send_ack(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) { ip4_addr_t client; - bool is_dhcp_parse_end = false; struct dhcps_state s; client.addr = *((uint32_t *) &dhcps->client_address); @@ -917,38 +917,52 @@ static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) DHCPS_LOG("dhcps: (s16_t)*optptr = %d\n", (s16_t)*optptr); #endif + if (*optptr == DHCP_OPTION_PAD) { + optptr++; + continue; + } + + if (*optptr == DHCP_OPTION_END) { + break; + } + + if (optptr + 1 >= end) { + break; + } + + u8_t opt_len = optptr[1]; + + if (optptr + 2 + opt_len > end) { + break; + } + switch ((s16_t) *optptr) { case DHCP_OPTION_MSG_TYPE: //53 - type = *(optptr + 2); + if (opt_len >= 1) { + type = optptr[2]; + } break; case DHCP_OPTION_REQ_IPADDR://50 - if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { + if (opt_len >= 4) { + if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); #endif - s.state = DHCPS_STATE_ACK; - } else { + s.state = DHCPS_STATE_ACK; + } else { #if DHCPS_DEBUG - DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); #endif - s.state = DHCPS_STATE_NAK; + s.state = DHCPS_STATE_NAK; + } } break; - - case DHCP_OPTION_END: { - is_dhcp_parse_end = true; - } - break; - } - - if (is_dhcp_parse_end) { - break; } - optptr += optptr[1] + 2; + optptr += opt_len + 2; } switch (type) {
Vulnerability mechanics
Root cause
"The DHCP server option parser does not validate option lengths against the packet buffer, allowing out-of-bounds reads."
Attack vector
An attacker on the same Layer-2 network can send a crafted DHCP request to a device running the ESP-IDF DHCP server. This request exploits the parser's failure to validate option lengths, causing it to read past the end of the buffer into adjacent heap memory. This can lead to a denial of service by crashing the DHCP server task or corrupting its state, preventing address assignment to clients [ref_id=1].
Affected code
The vulnerability resides in the `parse_options()` function within `components/lwip/apps/dhcpserver/dhcpserver.c` [ref_id=1]. The function iterates through the BOOTP/DHCP options field without proper validation of option lengths against the received packet buffer.
What the fix does
The patch hardens the option parser by adding checks to validate option bounds before processing them. Specifically, it ensures that the option length byte and the declared payload length do not exceed the buffer boundaries. The parser now explicitly skips DHCP_OPTION_PAD, terminates on DHCP_OPTION_END, and checks that the option length is sufficient for the data it consumes, preventing out-of-bounds reads [ref_id=1]. The affected commits are [patch_id=5423955], [patch_id=5423956], [patch_id=5423957], [patch_id=5423958], [patch_id=5423959], and [patch_id=5423960].
Preconditions
- configThe affected device must be configured to act as a DHCP server, typically via ESP-IDF's SoftAP functionality.
- networkThe attacker must be on the same Layer-2 network as the vulnerable device.
Generated on Jun 10, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/espressif/esp-idf/commit/2bf4dd12002dbae60a4b21abff010ecb2b8ee82bnvd
- github.com/espressif/esp-idf/commit/2da2db43fd7e0bcff9e7b95f54f388296bb6f911nvd
- github.com/espressif/esp-idf/commit/8b4b5d5301815198d177974ffc24848f47748248nvd
- github.com/espressif/esp-idf/commit/9f713dbc94982d917f2d12964b233cd9efa4aebanvd
- github.com/espressif/esp-idf/commit/d51b1076092487e533eadf8b48c9c8579d3a6712nvd
- github.com/espressif/esp-idf/commit/fba5f995436a3e3139f768b6d8f1a74d5ce1d318nvd
- github.com/espressif/esp-idf/security/advisories/GHSA-g764-gwc3-75m5nvd
News mentions
0No linked articles in our index yet.