hibernate-validator/CVE-2020-10693-4.patch
2021-03-16 09:27:59 +08:00

85 lines
3.3 KiB
Diff

From 93c027b954d4ccce1ad82b2f5e27e22357757fa8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= <yoann@hibernate.org>
Date: Mon, 24 Feb 2020 17:23:37 +0100
Subject: [PATCH] HV-1774 Test arbitrary code injection through
buildConstraintViolationWithTemplate()
---
.../ConstraintValidatorContextTest.java | 51 +++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/engine/src/test/java/org/hibernate/validator/test/constraints/ConstraintValidatorContextTest.java b/engine/src/test/java/org/hibernate/validator/test/constraints/ConstraintValidatorContextTest.java
index 6094195e3..a89a97016 100644
--- a/engine/src/test/java/org/hibernate/validator/test/constraints/ConstraintValidatorContextTest.java
+++ b/engine/src/test/java/org/hibernate/validator/test/constraints/ConstraintValidatorContextTest.java
@@ -194,6 +194,20 @@ public void testAddParameterNodeForFieldLevelConstraintCausesException() throws
}
}
+ @Test
+ public void testInjectionCausedByRecklessConcatenation() {
+ String maliciousPayload = "$\\A{1 + 1}";
+
+ // Simulate user entry, through a web form for example
+ MyObjectWithELInjectionRiskCausedByRecklessConcatenation object = new MyObjectWithELInjectionRiskCausedByRecklessConcatenation();
+ object.field1 = maliciousPayload;
+ Set<ConstraintViolation<MyObjectWithELInjectionRiskCausedByRecklessConcatenation>> constraintViolations = validator.validate( object );
+ assertThat( constraintViolations ).containsOnlyViolations(
+ violationOf( ValidationWithELInjectionRiskCausedByRecklessConcatenation.class )
+ .withMessage( "Value '" + maliciousPayload + "' is invalid" )
+ );
+ }
+
@MyClassLevelValidation
private static class MyObject {
@NotNull
@@ -264,6 +278,13 @@ public String getName() {
}
}
+ @ValidationWithELInjectionRiskCausedByRecklessConcatenation
+ private static class MyObjectWithELInjectionRiskCausedByRecklessConcatenation {
+
+ String field1;
+
+ }
+
@Retention(RUNTIME)
@Constraint(validatedBy = MyClassLevelValidation.Validator.class)
public @interface MyClassLevelValidation {
@@ -496,4 +517,34 @@ public boolean isValid(String value, ConstraintValidatorContext context) {
}
}
+
+ @Retention(RUNTIME)
+ @Constraint(validatedBy = ValidationWithELInjectionRiskCausedByRecklessConcatenation.Validator.class)
+ public @interface ValidationWithELInjectionRiskCausedByRecklessConcatenation {
+ String message() default "failed";
+
+ Class<?>[] groups() default { };
+
+ Class<? extends Payload>[] payload() default { };
+
+ class Validator
+ implements ConstraintValidator<ValidationWithELInjectionRiskCausedByRecklessConcatenation, MyObjectWithELInjectionRiskCausedByRecklessConcatenation> {
+
+ @Override
+ public boolean isValid(MyObjectWithELInjectionRiskCausedByRecklessConcatenation value, ConstraintValidatorContext context) {
+ context.disableDefaultConstraintViolation();
+
+ // This is bad practice: message parameters should be used instead.
+ // Regardless, it can happen and should work as well as possible.
+ context.buildConstraintViolationWithTemplate( "Value '" + escape( value.field1 ) + "' is invalid" )
+ .addConstraintViolation();
+
+ return false;
+ }
+
+ private String escape(String value) {
+ return value.replaceAll( "\\$+\\{", "{" );
+ }
+ }
+ }
}