@@ -208,6 +208,20 @@ public void testAddParameterNodeForFieldLevelConstraintCausesException() throws
208
208
}
209
209
}
210
210
211
+ @ Test
212
+ public void testInjectionCausedByRecklessConcatenation () {
213
+ String maliciousPayload = "$\\ A{1 + 1}" ;
214
+
215
+ // Simulate user entry, through a web form for example
216
+ MyObjectWithELInjectionRiskCausedByRecklessConcatenation object = new MyObjectWithELInjectionRiskCausedByRecklessConcatenation ();
217
+ object .field1 = maliciousPayload ;
218
+ Set <ConstraintViolation <MyObjectWithELInjectionRiskCausedByRecklessConcatenation >> constraintViolations = validator .validate ( object );
219
+ assertThat ( constraintViolations ).containsOnlyViolations (
220
+ violationOf ( ValidationWithELInjectionRiskCausedByRecklessConcatenation .class )
221
+ .withMessage ( "Value '" + maliciousPayload + "' is invalid" )
222
+ );
223
+ }
224
+
211
225
@ MyClassLevelValidation
212
226
private static class MyObject {
213
227
@ NotNull
@@ -278,6 +292,13 @@ public String getName() {
278
292
}
279
293
}
280
294
295
+ @ ValidationWithELInjectionRiskCausedByRecklessConcatenation
296
+ private static class MyObjectWithELInjectionRiskCausedByRecklessConcatenation {
297
+
298
+ String field1 ;
299
+
300
+ }
301
+
281
302
@ Retention (RUNTIME )
282
303
@ Constraint (validatedBy = MyClassLevelValidation .Validator .class )
283
304
public @interface MyClassLevelValidation {
@@ -486,4 +507,34 @@ public boolean isValid(String value, ConstraintValidatorContext context) {
486
507
}
487
508
}
488
509
}
510
+
511
+ @ Retention (RUNTIME )
512
+ @ Constraint (validatedBy = ValidationWithELInjectionRiskCausedByRecklessConcatenation .Validator .class )
513
+ public @interface ValidationWithELInjectionRiskCausedByRecklessConcatenation {
514
+ String message () default "failed" ;
515
+
516
+ Class <?>[] groups () default { };
517
+
518
+ Class <? extends Payload >[] payload () default { };
519
+
520
+ class Validator
521
+ implements ConstraintValidator <ValidationWithELInjectionRiskCausedByRecklessConcatenation , MyObjectWithELInjectionRiskCausedByRecklessConcatenation > {
522
+
523
+ @ Override
524
+ public boolean isValid (MyObjectWithELInjectionRiskCausedByRecklessConcatenation value , ConstraintValidatorContext context ) {
525
+ context .disableDefaultConstraintViolation ();
526
+
527
+ // This is bad practice: message parameters should be used instead.
528
+ // Regardless, it can happen and should work as well as possible.
529
+ context .buildConstraintViolationWithTemplate ( "Value '" + escape ( value .field1 ) + "' is invalid" )
530
+ .addConstraintViolation ();
531
+
532
+ return false ;
533
+ }
534
+
535
+ private String escape (String value ) {
536
+ return value .replaceAll ( "\\ $+\\ {" , "{" );
537
+ }
538
+ }
539
+ }
489
540
}
0 commit comments