From cec6f5bff4ec09a7377c31166b3ce4f58c9a8d86 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Sat, 4 Apr 2026 14:17:00 +0530 Subject: [PATCH] fix(esp_http_client): require https->https for cross-scheme redirects esp_http_client_set_redirection() now rejects any redirect target whose scheme is not https:// when the origin is HTTPS. This catches http, ftp, ws and any other scheme before client state is mutated. Same-host / https-to-https redirects are unaffected. Apps that intentionally want mixed-scheme redirects can set disable_auto_redirect=true and handle HTTP_EVENT_REDIRECT. --- components/esp_common/src/esp_err_to_name.c | 4 ++++ components/esp_http_client/esp_http_client.c | 20 ++++++++++++++++--- .../esp_http_client/include/esp_http_client.h | 1 + 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/components/esp_common/src/esp_err_to_name.c b/components/esp_common/src/esp_err_to_name.c index 4503b0b11fc..9e613764b5b 100644 --- a/components/esp_common/src/esp_err_to_name.c +++ b/components/esp_common/src/esp_err_to_name.c @@ -682,6 +682,10 @@ static const esp_err_msg_t esp_err_msg_table[] = { # ifdef ESP_ERR_HTTP_INCOMPLETE_DATA ERR_TBL_IT(ESP_ERR_HTTP_INCOMPLETE_DATA), /* 28684 0x700c Incomplete data received, less than Content-Length or last chunk */ +# endif +# ifdef ESP_ERR_HTTP_REDIRECT_DOWNGRADE + ERR_TBL_IT(ESP_ERR_HTTP_REDIRECT_DOWNGRADE), /* 28685 0x700d HTTPS origin redirected to a non-HTTPS + scheme (downgrade blocked) */ # endif // components/esp-tls/esp_tls_errors.h # ifdef ESP_ERR_ESP_TLS_BASE diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index ea4e7a034d5..1567cd21cdb 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -1151,6 +1151,19 @@ esp_err_t esp_http_client_set_redirection(esp_http_client_handle_t client) return ESP_ERR_INVALID_ARG; } ESP_LOGD(TAG, "Redirect to %s", client->location); + + /* On an HTTPS origin, only allow https:// redirect targets. Any other + * scheme (http, ftp, ws, ...) is rejected before client state is + * modified to prevent transport-layer downgrade attacks. */ + if (client->connection_info.scheme != NULL && + strcasecmp(client->connection_info.scheme, "https") == 0 && + strncasecmp(client->location, "https://", 8) != 0) { + ESP_LOGE(TAG, "HTTPS origin can only redirect to https:// targets (got %s). " + "Set disable_auto_redirect and handle manually if intended.", + client->location); + return ESP_ERR_HTTP_REDIRECT_DOWNGRADE; + } + esp_err_t err = esp_http_client_set_url(client, client->location); if (err == ESP_OK) { client->redirect_counter ++; @@ -1187,9 +1200,10 @@ static esp_err_t esp_http_check_response(esp_http_client_handle_t client) if (client->disable_auto_redirect) { http_dispatch_event(client, HTTP_EVENT_REDIRECT, NULL, 0); } else { - if (esp_http_client_set_redirection(client) != ESP_OK){ - return ESP_FAIL; - }; + esp_err_t redir_err = esp_http_client_set_redirection(client); + if (redir_err != ESP_OK) { + return redir_err; + } } esp_http_client_redirect_event_data_t evt_data = { .status_code = client->response->status_code, diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index 45229685149..4a257808778 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -297,6 +297,7 @@ typedef enum { #define ESP_ERR_HTTP_RANGE_NOT_SATISFIABLE (ESP_ERR_HTTP_BASE + 10) /*!< HTTP 416 Range Not Satisfiable, requested range in header is incorrect */ #define ESP_ERR_HTTP_READ_TIMEOUT (ESP_ERR_HTTP_BASE + 11) /*!< HTTP data read timeout */ #define ESP_ERR_HTTP_INCOMPLETE_DATA (ESP_ERR_HTTP_BASE + 12) /*!< Incomplete data received, less than Content-Length or last chunk */ +#define ESP_ERR_HTTP_REDIRECT_DOWNGRADE (ESP_ERR_HTTP_BASE + 13) /*!< HTTPS origin redirected to a non-HTTPS scheme (downgrade blocked) */ /** * @brief Start a HTTP session