Skip to content

Commit 965a639

Browse files
sbrannenbclozel
authored andcommitted
Limit SpEL expression length
This commit enforces a limit of the maximum size of a single SpEL expression. Closes gh-30330
1 parent cbbb287 commit 965a639

File tree

3 files changed

+45
-11
lines changed

3 files changed

+45
-11
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,15 +264,19 @@ public enum SpelMessage {
264264

265265
/** @since 5.2.23 */
266266
MAX_REPEATED_TEXT_SIZE_EXCEEDED(Kind.ERROR, 1076,
267-
"Repeated text results in too many characters, exceeding the threshold of ''{0}''"),
267+
"Repeated text is too long, exceeding the threshold of ''{0}'' characters"),
268268

269269
/** @since 5.2.23 */
270270
MAX_REGEX_LENGTH_EXCEEDED(Kind.ERROR, 1077,
271-
"Regular expression contains too many characters, exceeding the threshold of ''{0}''"),
271+
"Regular expression is too long, exceeding the threshold of ''{0}'' characters"),
272272

273273
/** @since 5.2.24 */
274274
MAX_CONCATENATED_STRING_LENGTH_EXCEEDED(Kind.ERROR, 1078,
275-
"Concatenated string is too long, exceeding the threshold of ''{0}'' characters");
275+
"Concatenated string is too long, exceeding the threshold of ''{0}'' characters"),
276+
277+
/** @since 5.2.24 */
278+
MAX_EXPRESSION_LENGTH_EXCEEDED(Kind.ERROR, 1079,
279+
"SpEL expression is too long, exceeding the threshold of ''{0}'' characters");
276280

277281

278282
private final Kind kind;

spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.expression.ParserContext;
3030
import org.springframework.expression.common.TemplateAwareExpressionParser;
3131
import org.springframework.expression.spel.InternalParseException;
32+
import org.springframework.expression.spel.SpelEvaluationException;
3233
import org.springframework.expression.spel.SpelMessage;
3334
import org.springframework.expression.spel.SpelParseException;
3435
import org.springframework.expression.spel.SpelParserConfiguration;
@@ -92,6 +93,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
9293

9394
private static final Pattern VALID_QUALIFIED_ID_PATTERN = Pattern.compile("[\\p{L}\\p{N}_$]+");
9495

96+
/**
97+
* Maximum length permitted for a SpEL expression.
98+
* @since 5.2.24
99+
*/
100+
private static final int MAX_EXPRESSION_LENGTH = 10_000;
101+
95102

96103
private final SpelParserConfiguration configuration;
97104

@@ -127,6 +134,8 @@ public InternalSpelExpressionParser(SpelParserConfiguration configuration) {
127134
protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context)
128135
throws ParseException {
129136

137+
checkExpressionLength(expressionString);
138+
130139
try {
131140
this.expressionString = expressionString;
132141
Tokenizer tokenizer = new Tokenizer(expressionString);
@@ -148,6 +157,12 @@ protected SpelExpression doParseExpression(String expressionString, @Nullable Pa
148157
}
149158
}
150159

160+
private void checkExpressionLength(String string) {
161+
if (string.length() > MAX_EXPRESSION_LENGTH) {
162+
throw new SpelEvaluationException(SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED, MAX_EXPRESSION_LENGTH);
163+
}
164+
}
165+
151166
// expression
152167
// : logicalOrExpression
153168
// ( (ASSIGN^ logicalOrExpression)

spring-expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,20 @@
5959
*/
6060
public class EvaluationTests extends AbstractExpressionTests {
6161

62+
@Test
63+
void expressionLength() {
64+
String expression = String.format("'X' + '%s'", repeat(" ", 9_992));
65+
assertThat(expression).hasSize(10_000);
66+
Expression expr = parser.parseExpression(expression);
67+
String result = expr.getValue(context, String.class);
68+
assertThat(result).hasSize(9_993);
69+
assertThat(result.trim()).isEqualTo("X");
70+
71+
expression = String.format("'X' + '%s'", repeat(" ", 9_993));
72+
assertThat(expression).hasSize(10_001);
73+
evaluateAndCheckError(expression, String.class, SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED);
74+
}
75+
6276
@Test
6377
public void testCreateListsOnAttemptToIndexNull01() throws EvaluationException, ParseException {
6478
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
@@ -211,14 +225,6 @@ void matchesWithPatternLengthThreshold() {
211225
evaluateAndCheckError("'abc' matches '" + pattern + "'", Boolean.class, SpelMessage.MAX_REGEX_LENGTH_EXCEEDED);
212226
}
213227

214-
private String repeat(String str, int count) {
215-
String result = "";
216-
for (int i = 0; i < count; i++) {
217-
result += str;
218-
}
219-
return result;
220-
}
221-
222228
// mixing operators
223229
@Test
224230
public void testMixingOperators01() {
@@ -1373,6 +1379,15 @@ public List<Method> filter(List<Method> methods) {
13731379
}
13741380

13751381

1382+
private static String repeat(String str, int count) {
1383+
String result = "";
1384+
for (int i = 0; i < count; i++) {
1385+
result += str;
1386+
}
1387+
return result;
1388+
}
1389+
1390+
13761391
@SuppressWarnings("rawtypes")
13771392
static class TestClass {
13781393

0 commit comments

Comments
 (0)