diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index 8eee47055a1..b9abe16a831 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -474,10 +474,17 @@ esp_err_t esp_http_client_set_username(esp_http_client_handle_t client, const ch ESP_LOGE(TAG, "client must not be NULL"); return ESP_ERR_INVALID_ARG; } + /* Duplicate first so that passing the current username back in (e.g. the pointer + * returned by esp_http_client_get_username()) is safe: the old buffer is freed only + * after the copy succeeds, avoiding a use-after-free on self-aliasing (CWE-416). */ + char *new_username = username ? strdup(username) : NULL; + if (username != NULL && new_username == NULL) { + return ESP_ERR_NO_MEM; + } if (client->connection_info.username != NULL) { free(client->connection_info.username); } - client->connection_info.username = username ? strdup(username) : NULL; + client->connection_info.username = new_username; return ESP_OK; } @@ -520,11 +527,19 @@ esp_err_t esp_http_client_set_password(esp_http_client_handle_t client, const ch ESP_LOGE(TAG, "client must not be NULL"); return ESP_ERR_INVALID_ARG; } + /* Duplicate first so that passing the current password back in (e.g. the pointer + * returned by esp_http_client_get_password()) is safe: zeroize and free the old buffer + * only after the copy succeeds, avoiding a use-after-free / credential corruption + * (CWE-416) caused by memset zeroing the source before strdup reads it. */ + char *new_password = password ? strdup(password) : NULL; + if (password != NULL && new_password == NULL) { + return ESP_ERR_NO_MEM; + } if (client->connection_info.password != NULL) { memset(client->connection_info.password, 0, strlen(client->connection_info.password)); free(client->connection_info.password); } - client->connection_info.password = password ? strdup(password) : NULL; + client->connection_info.password = new_password; return ESP_OK; } @@ -1720,14 +1735,17 @@ static esp_err_t esp_http_client_connect(esp_http_client_handle_t client) } } client->state = HTTP_STATE_CONNECTED; - http_dispatch_event(client, HTTP_EVENT_ON_CONNECTED, NULL, 0); - http_dispatch_event_to_event_loop(HTTP_EVENT_ON_CONNECTED, &client, sizeof(esp_http_client_handle_t)); #ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS + /* Perform handle-dependent session-ticket bookkeeping before dispatching the user + * callback: a synchronous HTTP_EVENT_ON_CONNECTED handler is permitted to destroy + * the client, so dereferencing the handle afterwards would be a UAF (CWE-416). */ if (client->session_ticket_state != SESSION_TICKET_UNUSED) { esp_transport_ssl_session_ticket_operation(client->transport, ESP_TRANSPORT_SESSION_TICKET_SAVE); client->session_ticket_state = SESSION_TICKET_SAVED; } #endif + http_dispatch_event(client, HTTP_EVENT_ON_CONNECTED, NULL, 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ON_CONNECTED, &client, sizeof(esp_http_client_handle_t)); } return ESP_OK; diff --git a/components/esp_http_client/lib/http_auth.c b/components/esp_http_client/lib/http_auth.c index 9e5477cd1f1..23aee240c11 100644 --- a/components/esp_http_client/lib/http_auth.c +++ b/components/esp_http_client/lib/http_auth.c @@ -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 */ @@ -201,11 +201,18 @@ char *http_auth_digest(const char *username, const char *password, esp_http_auth if (rc < 0) { ESP_LOGE(TAG, "asprintf() returned: %d", rc); ret = ESP_FAIL; + free(auth_str); + auth_str = NULL; goto _digest_exit; } + /* http_utils_append_string() realloc()s auth_str; on failure it returns NULL + * without freeing the original buffer, so keep a handle to free it here. */ + char *prev_auth_str = auth_str; auth_str = http_utils_append_string(&auth_str, temp_auth_str, strlen(temp_auth_str)); if (!auth_str) { ret = ESP_FAIL; + free(prev_auth_str); + free(temp_auth_str); goto _digest_exit; } free(temp_auth_str);