Skip to content

Commit b85e42b

Browse files
committed
Prevents reflection of user input when reporting URI validation errors as part of 400 response.
1 parent c325930 commit b85e42b

File tree

3 files changed

+26
-10
lines changed

3 files changed

+26
-10
lines changed

common/uri/src/main/java/io/helidon/common/uri/UriValidationException.java

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024 Oracle and/or its affiliates.
2+
* Copyright (c) 2024, 2025 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -38,6 +38,10 @@ public class UriValidationException extends IllegalArgumentException {
3838
* The value (containing illegal characters) that failed validation.
3939
*/
4040
private final char[] invalidValue;
41+
/**
42+
* The index of the invalid char.
43+
*/
44+
private final int index;
4145

4246
/**
4347
* Create a new validation exception that uses a descriptive message and the failed chars.
@@ -52,6 +56,7 @@ public UriValidationException(Segment segment, char[] invalidValue, String messa
5256

5357
this.segment = segment;
5458
this.invalidValue = invalidValue;
59+
this.index = -1;
5560
}
5661

5762
/**
@@ -67,6 +72,7 @@ public UriValidationException(Segment segment, char[] invalidValue, String messa
6772

6873
this.segment = segment;
6974
this.invalidValue = invalidValue;
75+
this.index = -1;
7076
}
7177

7278
/**
@@ -84,6 +90,7 @@ public UriValidationException(Segment segment, char[] invalidValue, String messa
8490

8591
this.segment = segment;
8692
this.invalidValue = invalidValue;
93+
this.index = index;
8794
}
8895

8996
/**
@@ -100,6 +107,7 @@ public UriValidationException(Segment segment, char[] invalidValue, String messa
100107

101108
this.segment = segment;
102109
this.invalidValue = invalidValue;
110+
this.index = index;
103111
}
104112

105113
/**
@@ -121,6 +129,16 @@ public Segment segment() {
121129
return segment;
122130
}
123131

132+
/**
133+
* Returns a safe message that does not include any user input and can be returned
134+
* as part of a response.
135+
*
136+
* @return a safe message
137+
*/
138+
public String safeMessage() {
139+
return segment.text() + " contains invalid char" + (index != -1 ? " at index " + index : "");
140+
}
141+
124142
private static String toMessage(char[] value, String message) {
125143
Objects.requireNonNull(value);
126144
Objects.requireNonNull(message);

webserver/tests/webserver/src/test/java/io/helidon/webserver/tests/BadPrologueTest.java

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024 Oracle and/or its affiliates.
2+
* Copyright (c) 2024, 2025 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -76,9 +76,8 @@ void testBadQuery() {
7676

7777
assertThat(response, containsString("400 Bad Request"));
7878
// beginning of message to the first double quote
79-
assertThat(response, containsString("Query contains invalid char: "));
79+
assertThat(response, containsString("Query contains invalid char at index 2"));
8080
// end of message from double quote, index of bad char, and bad char
81-
assertThat(response, containsString(", index: 2, char: 0x3c"));
8281
assertThat(response, not(containsString(">")));
8382
}
8483

@@ -91,9 +90,8 @@ void testBadQueryCurly() {
9190

9291
assertThat(response, containsString("400 Bad Request"));
9392
// beginning of message to the first double quote
94-
assertThat(response, containsString("Query contains invalid char: "));
93+
assertThat(response, containsString("Query contains invalid char at index 10"));
9594
// end of message from double quote, index of bad char, and bad char
96-
assertThat(response, containsString(", index: 10, char: 0x7b"));
9795
}
9896

9997
@Test
@@ -117,9 +115,8 @@ void testBadFragment() {
117115

118116
assertThat(response, containsString("400 Bad Request"));
119117
// beginning of message to the first double quote
120-
assertThat(response, containsString("Fragment contains invalid char: "));
118+
assertThat(response, containsString("Fragment contains invalid char at index 16"));
121119
// end of message from double quote, index of bad char, and bad char
122-
assertThat(response, containsString(", index: 16, char: 0x3e"));
123120
assertThat(response, not(containsString(">")));
124121
}
125122
}

webserver/webserver/src/main/java/io/helidon/webserver/http1/Http1Connection.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, 2024 Oracle and/or its affiliates.
2+
* Copyright (c) 2022, 2025 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,6 +37,7 @@
3737
import io.helidon.common.mapper.MapperException;
3838
import io.helidon.common.task.InterruptableTask;
3939
import io.helidon.common.tls.TlsUtils;
40+
import io.helidon.common.uri.UriValidationException;
4041
import io.helidon.common.uri.UriValidator;
4142
import io.helidon.http.BadRequestException;
4243
import io.helidon.http.DateTime;
@@ -335,7 +336,7 @@ private void validatePrologue(HttpPrologue prologue) {
335336
.status(Status.BAD_REQUEST_400)
336337
.request(DirectTransportRequest.create(prologue, ServerRequestHeaders.create()))
337338
.setKeepAlive(false)
338-
.message(e.getMessage())
339+
.message(e instanceof UriValidationException ve ? ve.safeMessage() : e.getMessage())
339340
.safeMessage(true)
340341
.cause(e)
341342
.build();

0 commit comments

Comments
 (0)