Security Vulnerability Report
Repository: espressif/arduino-esp32
File: libraries/WebServer/src/WebServer.cpp
Function: void WebServer::sendHeader(const String& name, const String& value, bool first)
Lines: 504–521, 577-582
Code Snippet
Headers are added to the server response here:
|
void WebServer::sendHeader(const String &name, const String &value, bool first) { |
|
RequestArgument *header = new RequestArgument(); |
|
header->key = name; |
|
header->value = value; |
|
|
|
if (!_responseHeaders || first) { |
|
header->next = _responseHeaders; |
|
_responseHeaders = header; |
|
} else { |
|
RequestArgument *last = _responseHeaders; |
|
while (last->next) { |
|
last = last->next; |
|
} |
|
last->next = header; |
|
} |
|
|
|
_responseHeaderCount++; |
|
} |
void WebServer::sendHeader(const String &name, const String &value, bool first) {
RequestArgument *header = new RequestArgument();
header->key = name;
header->value = value;
if (!_responseHeaders || first) {
header->next = _responseHeaders;
_responseHeaders = header;
} else {
RequestArgument *last = _responseHeaders;
while (last->next) {
last = last->next;
}
last->next = header;
}
_responseHeaderCount++;
}
Those headers are concatenated into the HTTP response body here:
|
for (RequestArgument *header = _responseHeaders; header; header = header->next) { |
|
response.concat(header->key); |
|
response.concat(F(": ")); |
|
response.concat(header->value); |
|
response.concat(F("\r\n")); |
|
} |
for (RequestArgument *header = _responseHeaders; header; header = header->next) {
response.concat(header->key);
response.concat(F(": "));
response.concat(header->value);
response.concat(F("\r\n"));
}
Vulnerability Overview
Type: HTTP Response Splitting (CWE-113)
Description:
The sendHeader
function takes arbitrary input for the HTTP header name and value, concatenates them into an HTTP header line, and appends this to the outgoing HTTP response headers. There is no validation or sanitization of the name
or value
parameters before they are included in the HTTP response.
If an attacker can control the input to sendHeader
(either directly or indirectly), they could inject carriage return (\r
) or line feed (\n
) characters into either the header name or value. This could allow the attacker to:
- Inject additional headers
- Manipulate the structure of the HTTP response
- Potentially inject an entire new HTTP response (HTTP Response Splitting)
- Cause header confusion or other HTTP protocol attacks
Impact:
-
HTTP Response Splitting: If user-supplied input is passed to sendHeader
without sanitization, an attacker could perform HTTP response splitting, leading to:
- Cross-site scripting (XSS)
- Cache poisoning
- Session fixation
- Bypassing CORS or security headers
-
General Protocol Violation: Invalid HTTP headers or malformed responses, potentially breaking clients or enabling additional attacks.
Example Attack Scenario
If an attacker can cause a value such as:
attacker_value = "injected\r\nSet-Cookie: session=evil"
to be passed as the value
argument, the resulting HTTP response would contain:
Header-Name: injected
Set-Cookie: session=evil
This would let the attacker set arbitrary headers or even break the response into separate responses.
Recommendation
Input Validation:
- Reject or sanitize any
\r
(carriage return) or \n
(line feed) characters in both the header name and value.
- Only allow printable ASCII characters for header names.
- Consider providing a whitelisted set of allowed headers, or at least validating against a strict header name pattern.
Example Fix:
void WebServer::sendHeader(const String& name, const String& value, bool first) {
if (name.indexOf('\r') != -1 || name.indexOf('\n') != -1 ||
value.indexOf('\r') != -1 || value.indexOf('\n') != -1) {
log_e("Invalid character in HTTP header name or value");
return;
}
RequestArgument *header = new RequestArgument();
header->key = name;
header->value = value;
if (!_responseHeaders || first) {
header->next = _responseHeaders;
_responseHeaders = header;
} else {
RequestArgument *last = _responseHeaders;
while (last->next) {
last = last->next;
}
last->next = header;
}
_responseHeaderCount++;
}
Fix
This vulnerability is addressed in this commit: 21640ac
It has been patched in versions: >= 3.3.0-RC1, >= 3.2.1
References
Severity
High — If user input is ever passed to this function without validation, this can lead to serious web security issues, including XSS and session hijacking.
Security Vulnerability Report
Repository: espressif/arduino-esp32
File: libraries/WebServer/src/WebServer.cpp
Function:
void WebServer::sendHeader(const String& name, const String& value, bool first)
Lines: 504–521, 577-582
Code Snippet
Headers are added to the server response here:
arduino-esp32/libraries/WebServer/src/WebServer.cpp
Lines 504 to 521 in 9e61fa7
Those headers are concatenated into the HTTP response body here:
arduino-esp32/libraries/WebServer/src/WebServer.cpp
Lines 577 to 582 in 9e61fa7
Vulnerability Overview
Type: HTTP Response Splitting (CWE-113)
Description:
The
sendHeader
function takes arbitrary input for the HTTP header name and value, concatenates them into an HTTP header line, and appends this to the outgoing HTTP response headers. There is no validation or sanitization of thename
orvalue
parameters before they are included in the HTTP response.If an attacker can control the input to
sendHeader
(either directly or indirectly), they could inject carriage return (\r
) or line feed (\n
) characters into either the header name or value. This could allow the attacker to:Impact:
HTTP Response Splitting: If user-supplied input is passed to
sendHeader
without sanitization, an attacker could perform HTTP response splitting, leading to:General Protocol Violation: Invalid HTTP headers or malformed responses, potentially breaking clients or enabling additional attacks.
Example Attack Scenario
If an attacker can cause a value such as:
to be passed as the
value
argument, the resulting HTTP response would contain:This would let the attacker set arbitrary headers or even break the response into separate responses.
Recommendation
Input Validation:
\r
(carriage return) or\n
(line feed) characters in both the header name and value.Example Fix:
Fix
This vulnerability is addressed in this commit: 21640ac
It has been patched in versions:
>= 3.3.0-RC1, >= 3.2.1
References
Severity
High — If user input is ever passed to this function without validation, this can lead to serious web security issues, including XSS and session hijacking.