Skip to content

Commit ebc8265

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-30329
1 parent 8645746 commit ebc8265

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

+7-3
Original file line numberDiff line numberDiff line change
@@ -268,15 +268,19 @@ public enum SpelMessage {
268268

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

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

277277
/** @since 5.2.24 */
278278
MAX_CONCATENATED_STRING_LENGTH_EXCEEDED(Kind.ERROR, 1078,
279-
"Concatenated string is too long, exceeding the threshold of ''{0}'' characters");
279+
"Concatenated string is too long, exceeding the threshold of ''{0}'' characters"),
280+
281+
/** @since 5.2.24 */
282+
MAX_EXPRESSION_LENGTH_EXCEEDED(Kind.ERROR, 1079,
283+
"SpEL expression is too long, exceeding the threshold of ''{0}'' characters");
280284

281285

282286
private final Kind kind;

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

+15
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

+23-8
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,20 @@ class EvaluationTests extends AbstractExpressionTests {
6060
@Nested
6161
class MiscellaneousTests {
6262

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

495-
private String repeat(String str, int count) {
496-
String result = "";
497-
for (int i = 0; i < count; i++) {
498-
result += str;
499-
}
500-
return result;
501-
}
502-
503509
}
504510

505511
@Nested
@@ -1474,6 +1480,15 @@ private void expectFail(ExpressionParser parser, EvaluationContext eContext, Str
14741480
}
14751481

14761482

1483+
private static String repeat(String str, int count) {
1484+
String result = "";
1485+
for (int i = 0; i < count; i++) {
1486+
result += str;
1487+
}
1488+
return result;
1489+
}
1490+
1491+
14771492
@SuppressWarnings("rawtypes")
14781493
static class TestClass {
14791494

0 commit comments

Comments
 (0)