Skip to content

Commit ad1795b

Browse files
committed
Merge branch '4.0.x'
Closes gh-50216
2 parents 72cad8c + dfabb01 commit ad1795b

4 files changed

Lines changed: 76 additions & 5 deletions

File tree

module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/error/AbstractErrorWebExceptionHandler.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.boot.webflux.autoconfigure.error;
1818

1919
import java.util.Collections;
20-
import java.util.Date;
2120
import java.util.List;
2221
import java.util.Map;
2322

@@ -236,17 +235,17 @@ private boolean isTemplateAvailable(String viewName) {
236235
protected Mono<ServerResponse> renderDefaultErrorView(ServerResponse.BodyBuilder responseBody,
237236
Map<String, @Nullable Object> error) {
238237
StringBuilder builder = new StringBuilder();
239-
Date timestamp = (Date) error.get("timestamp");
238+
Object timestamp = error.get("timestamp");
240239
Object message = error.get("message");
241240
Object trace = error.get("trace");
242241
Object requestId = error.get("requestId");
243242
builder.append("<html><body><h1>Whitelabel Error Page</h1>")
244243
.append("<p>This application has no configured error view, so you are seeing this as a fallback.</p>")
245244
.append("<div id='created'>")
246-
.append(timestamp)
245+
.append(htmlEscape(timestamp))
247246
.append("</div>")
248247
.append("<div>[")
249-
.append(requestId)
248+
.append(htmlEscape(requestId))
250249
.append("] There was an unexpected error (type=")
251250
.append(htmlEscape(error.get("error")))
252251
.append(", status=")

module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/error/DefaultErrorWebExceptionHandlerIntegrationTests.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,29 @@ void escapeHtmlInDefaultErrorView() {
430430
});
431431
}
432432

433+
@Test
434+
void escapeHtmlInErrorAttributes() {
435+
this.contextRunner.withPropertyValues("spring.mustache.prefix=classpath:/unknown/")
436+
.withUserConfiguration(CustomErrorAttributesWithEscaping.class)
437+
.run((context) -> {
438+
WebTestClient client = getWebClient(context);
439+
String body = client.get()
440+
.uri("/")
441+
.accept(MediaType.TEXT_HTML)
442+
.exchange()
443+
.expectStatus()
444+
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
445+
.expectHeader()
446+
.contentType(TEXT_HTML_UTF8)
447+
.expectBody(String.class)
448+
.returnResult()
449+
.getResponseBody();
450+
assertThat(body).doesNotContain("<script>")
451+
.contains("&lt;script&gt;")
452+
.contains("xss-error", "xss-message", "xss-requestId", "xss-timestamp", "xss-trace");
453+
});
454+
}
455+
433456
@Test
434457
void testExceptionWithNullMessage() {
435458
this.contextRunner.withPropertyValues("spring.mustache.prefix=classpath:/unknown/").run((context) -> {
@@ -710,4 +733,29 @@ ErrorAttributes errorAttributes() {
710733

711734
}
712735

736+
@Configuration(proxyBeanMethods = false)
737+
static class CustomErrorAttributesWithEscaping {
738+
739+
@Bean
740+
ErrorAttributes errorAttributes() {
741+
return new DefaultErrorAttributes() {
742+
743+
@Override
744+
public Map<String, @Nullable Object> getErrorAttributes(ServerRequest request,
745+
ErrorAttributeOptions options) {
746+
Map<String, @Nullable Object> attributes = new LinkedHashMap<>(
747+
super.getErrorAttributes(request, options));
748+
attributes.put("error", "<script>alert('xss-error')</script>");
749+
attributes.put("message", "<script>alert('xss-message')</script>");
750+
attributes.put("requestId", "<script>alert('xss-requestId')</script>");
751+
attributes.put("timestamp", "<script>alert('xss-timestamp')</script>");
752+
attributes.put("trace", "<script>alert('xss-trace')</script>");
753+
return attributes;
754+
}
755+
756+
};
757+
}
758+
759+
}
760+
713761
}

module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/ErrorMvcAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ public void render(@Nullable Map<String, ?> model, HttpServletRequest request, H
216216
builder.append("<html><body><h1>Whitelabel Error Page</h1>")
217217
.append("<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>")
218218
.append("<div id='created'>")
219-
.append(timestamp)
219+
.append(htmlEscape(timestamp))
220220
.append("</div>")
221221
.append("<div>There was an unexpected error (type=")
222222
.append(htmlEscape(model.get("error")))

module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/error/ErrorMvcAutoConfigurationTests.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,30 @@ void renderCanUseJavaTimeTypeAsTimestamp() { // gh-23256
9090
});
9191
}
9292

93+
@Test
94+
void renderEscapesHtmlInErrorAttributes() {
95+
this.contextRunner.run((context) -> {
96+
View errorView = context.getBean("error", View.class);
97+
ErrorAttributes errorAttributes = context.getBean(ErrorAttributes.class);
98+
DispatcherServletWebRequest webRequest = createWebRequest(new IllegalStateException("Exception message"),
99+
false);
100+
Map<String, @Nullable Object> attributes = errorAttributes.getErrorAttributes(webRequest, withAllOptions());
101+
attributes.put("error", "<script>alert('xss-error')</script>");
102+
attributes.put("message", "<script>alert('xss-message')</script>");
103+
attributes.put("timestamp", "<script>alert('xss-timestamp')</script>");
104+
attributes.put("trace", "<script>alert('xss-trace')</script>");
105+
HttpServletResponse response = webRequest.getResponse();
106+
assertThat(response).isNotNull();
107+
errorView.render(attributes, webRequest.getRequest(), response);
108+
String responseString = ((MockHttpServletResponse) response).getContentAsString();
109+
assertThat(responseString).contains("&lt;script&gt;alert(&#39;xss-error&#39;)&lt;/script&gt;")
110+
.contains("&lt;script&gt;alert(&#39;xss-message&#39;)&lt;/script&gt;")
111+
.contains("&lt;script&gt;alert(&#39;xss-timestamp&#39;)&lt;/script&gt;")
112+
.contains("&lt;script&gt;alert(&#39;xss-trace&#39;)&lt;/script&gt;")
113+
.doesNotContain("<script>");
114+
});
115+
}
116+
93117
@Test
94118
void renderWhenAlreadyCommittedLogsMessage(CapturedOutput output) {
95119
this.contextRunner.run((context) -> {

0 commit comments

Comments
 (0)