feat(esp_http_server): adds check for crlf in response creation

This commit is contained in:
Ashish Sharma
2026-03-27 15:07:56 +08:00
parent 710f133604
commit 3c2f81c6a8
2 changed files with 54 additions and 1 deletions
+19 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2018-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -178,6 +178,12 @@ esp_err_t httpd_resp_set_hdr(httpd_req_t *r, const char *field, const char *valu
return ESP_ERR_HTTPD_INVALID_REQ;
}
/* Reject CRLF in header field or value */
if (strpbrk(field, "\r\n") || strpbrk(value, "\r\n")) {
ESP_LOGW(TAG, LOG_FMT("rejecting header with CRLF: %.32s"), field);
return ESP_ERR_INVALID_ARG;
}
struct httpd_req_aux *ra = r->aux;
struct httpd_data *hd = (struct httpd_data *) r->handle;
@@ -209,6 +215,12 @@ esp_err_t httpd_resp_set_status(httpd_req_t *r, const char *status)
return ESP_ERR_HTTPD_INVALID_REQ;
}
/* Reject CRLF in status */
if (strpbrk(status, "\r\n")) {
ESP_LOGW(TAG, LOG_FMT("rejecting status with CRLF: %.32s"), status);
return ESP_ERR_INVALID_ARG;
}
struct httpd_req_aux *ra = r->aux;
ra->status = (char *)status;
return ESP_OK;
@@ -228,6 +240,12 @@ esp_err_t httpd_resp_set_type(httpd_req_t *r, const char *type)
return ESP_ERR_HTTPD_INVALID_REQ;
}
/* Reject CRLF in content type */
if (strpbrk(type, "\r\n")) {
ESP_LOGW(TAG, LOG_FMT("rejecting content type with CRLF: %.32s"), type);
return ESP_ERR_INVALID_ARG;
}
struct httpd_req_aux *ra = r->aux;
ra->content_type = (char *)type;
return ESP_OK;
@@ -367,6 +367,41 @@ TEST_CASE("Interface Binding Test", "[HTTP SERVER]")
TEST_ASSERT(httpd_stop(hd2) == ESP_OK);
}
TEST_CASE("httpd_resp_set_hdr rejects CRLF in header field and value", "[HTTP SERVER][security]")
{
httpd_req_t fake_req = {0};
/* \r\n in value */
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG,
httpd_resp_set_hdr(&fake_req, "X-Field", "val\r\nX-Injected: pwned"));
/* bare \n in value */
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG,
httpd_resp_set_hdr(&fake_req, "X-Field", "val\nX-Injected: pwned"));
/* \r\n in field name */
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG,
httpd_resp_set_hdr(&fake_req, "X-Field\r\nX-Injected: pwned", "val"));
}
TEST_CASE("httpd_resp_set_status rejects CRLF in status string", "[HTTP SERVER][security]")
{
httpd_req_t fake_req = {0};
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG,
httpd_resp_set_status(&fake_req, "200 OK\r\nX-Injected: pwned"));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG,
httpd_resp_set_status(&fake_req, "200 OK\nX-Injected: pwned"));
}
TEST_CASE("httpd_resp_set_type rejects CRLF in content type", "[HTTP SERVER][security]")
{
httpd_req_t fake_req = {0};
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG,
httpd_resp_set_type(&fake_req, "text/html\r\nX-Injected: pwned"));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG,
httpd_resp_set_type(&fake_req, "text/html\nX-Injected: pwned"));
}
void app_main(void)
{
unity_run_menu();