Commit 4b360a61d6 for asterisk.org

commit 4b360a61d649a7c12b1021aa554642322ee28c10
Author: Milan Kyselica <mil.kyselica@gmail.com>
Date:   Wed Apr 8 20:02:19 2026 +0200

    http: Escape error page text to prevent reflected XSS

    The text parameter in ast_http_create_response() is inserted into
    the HTML body without escaping, while the server name on the same
    page is properly escaped via ast_xml_escape(). When res_phoneprov
    passes the decoded request URI as the text of a 404 response, HTML
    metacharacters in the URI are rendered by the browser.

    Apply ast_xml_escape() to the text parameter before inserting it
    into the HTML template, using the same function already used for
    the server name.

    Resolves: #GHSA-4pgv-j3mr-3rcp

diff --git a/main/http.c b/main/http.c
index 37d4d08a7e..5a04ffcf3e 100644
--- a/main/http.c
+++ b/main/http.c
@@ -634,6 +634,7 @@ void ast_http_create_response(struct ast_tcptls_session_instance *ser, int statu
 	const char *status_title, struct ast_str *http_header_data, const char *text)
 {
 	char server_name[MAX_SERVER_NAME_LENGTH];
+	char escaped_text[512];
 	struct ast_str *server_address = ast_str_create(MAX_SERVER_NAME_LENGTH);
 	struct ast_str *out = ast_str_create(INITIAL_RESPONSE_BODY_BUFFER);

@@ -656,6 +657,13 @@ void ast_http_create_response(struct ast_tcptls_session_instance *ser, int statu
 	                server_name);
 	}

+	/* Escape text to prevent reflected XSS in error pages */
+	if (!ast_strlen_zero(text)) {
+		ast_xml_escape(text, escaped_text, sizeof(escaped_text));
+	} else {
+		escaped_text[0] = '\0';
+	}
+
 	ast_str_set(&out,
 	            0,
 	            "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
@@ -670,7 +678,7 @@ void ast_http_create_response(struct ast_tcptls_session_instance *ser, int statu
 	            status_code,
 	            status_title,
 	            status_title,
-	            text ? text : "",
+	            escaped_text,
 	            ast_str_buffer(server_address));

 	ast_free(server_address);