VYPR
High severityNVD Advisory· Published Feb 24, 2020· Updated Aug 4, 2024

Remote Code Execution (RCE) vulnerability in dropwizard-validation

CVE-2020-5245

Description

Dropwizard-Validation prior to 1.3.19 and 2.0.2 allows arbitrary code execution via EL injection in the self-validating feature.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Dropwizard-Validation prior to 1.3.19 and 2.0.2 allows arbitrary code execution via EL injection in the self-validating feature.

CVE-2020-5245 is a critical vulnerability in Dropwizard-Validation that stems from the self-validating feature using Java Expression Language (EL) interpolation without proper sanitization. The Jakarta Bean Validation specification allows message expressions to be evaluated, which can include dynamic EL statements [2]. Dropwizard-Validation directly passes user-controlled constraint violation messages into the EL evaluation context, enabling injection of arbitrary EL expressions [1].

Attackers can exploit this by providing crafted input that triggers a validation error, where the violation message itself—or attributes derived from it—contains malicious EL. No authentication is required if the application exposes validation endpoints to untrusted users; the attacker only needs to supply input that violates a constraint with an interpolated message. The EL is executed in the context of the Dropwizard service account [3].

Successful exploitation permits remote code execution on the host system with the privileges of the Dropwizard service process, leading to full compromise of the application server, data exfiltration, or lateral movement within the network. Because the execution runs with the service account's permissions, the impact can range from data corruption to complete system takeover [3].

The vulnerability is patched in Dropwizard-Validation versions 1.3.19 and 2.0.2 [4]. The fix escapes EL expressions in the ViolationCollector, preventing the interpretation of user-supplied strings as executable code [4]. Users running earlier versions should upgrade immediately; no workaround exists other than disabling the self-validating feature if patching is not possible.

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
io.dropwizard:dropwizard-validationMaven
>= 1.3.0-rc1, < 1.3.191.3.19
io.dropwizard:dropwizard-validationMaven
>= 2.0.0, < 2.0.22.0.2

Affected products

2

Patches

2
28479f743a9d

Escape EL expressions in ViolationCollector (#3160)

https://github.com/dropwizard/dropwizardJochen SchalandaFeb 20, 2020via ghsa
2 files changed · +124 21
  • dropwizard-validation/src/main/java/io/dropwizard/validation/selfvalidating/ViolationCollector.java+75 5 modified
    @@ -1,12 +1,16 @@
     package io.dropwizard.validation.selfvalidating;
     
    +import javax.annotation.Nullable;
     import javax.validation.ConstraintValidatorContext;
    +import java.util.regex.Matcher;
    +import java.util.regex.Pattern;
     
     /**
      * This class is a simple wrapper around the ConstraintValidatorContext of hibernate validation.
      * It collects all the violations of the SelfValidation methods of an object.
      */
     public class ViolationCollector {
    +    private static final Pattern ESCAPE_PATTERN = Pattern.compile("\\$\\{");
     
         private boolean violationOccurred = false;
         private ConstraintValidatorContext context;
    @@ -17,14 +21,80 @@ public ViolationCollector(ConstraintValidatorContext context) {
         }
     
         /**
    -     * Adds a new violation to this collector. This also sets violationOccurred to true.
    +     * Adds a new violation to this collector. This also sets {@code violationOccurred} to {@code true}.
          *
    -     * @param msg the message of the violation
    +     * @param message the message of the violation (any EL expression will be escaped and not parsed)
          */
    -    public void addViolation(String msg) {
    +    public void addViolation(String message) {
             violationOccurred = true;
    -        context.buildConstraintViolationWithTemplate(msg)
    -            .addConstraintViolation();
    +        String messageTemplate = escapeEl(message);
    +        context.buildConstraintViolationWithTemplate(messageTemplate)
    +                .addConstraintViolation();
    +    }
    +
    +    /**
    +     * Adds a new violation to this collector. This also sets {@code violationOccurred} to {@code true}.
    +     *
    +     * @param propertyName the name of the property
    +     * @param message      the message of the violation (any EL expression will be escaped and not parsed)
    +     * @since 1.3.19
    +     */
    +    public void addViolation(String propertyName, String message) {
    +        violationOccurred = true;
    +        String messageTemplate = escapeEl(message);
    +        context.buildConstraintViolationWithTemplate(messageTemplate)
    +                .addPropertyNode(propertyName)
    +                .addConstraintViolation();
    +    }
    +
    +    /**
    +     * Adds a new violation to this collector. This also sets {@code violationOccurred} to {@code true}.
    +     *
    +     * @param propertyName the name of the property with the violation
    +     * @param index        the index of the element with the violation
    +     * @param message      the message of the violation (any EL expression will be escaped and not parsed)
    +     * @since 1.3.19
    +     */
    +    public void addViolation(String propertyName, Integer index, String message) {
    +        violationOccurred = true;
    +        String messageTemplate = escapeEl(message);
    +        context.buildConstraintViolationWithTemplate(messageTemplate)
    +                .addPropertyNode(propertyName)
    +                .addBeanNode().inIterable().atIndex(index)
    +                .addConstraintViolation();
    +    }
    +
    +    /**
    +     * Adds a new violation to this collector. This also sets {@code violationOccurred} to {@code true}.
    +     *
    +     * @param propertyName the name of the property with the violation
    +     * @param key          the key of the element with the violation
    +     * @param message      the message of the violation (any EL expression will be escaped and not parsed)
    +     * @since 1.3.19
    +     */
    +    public void addViolation(String propertyName, String key, String message) {
    +        violationOccurred = true;
    +        String messageTemplate = escapeEl(message);
    +        context.buildConstraintViolationWithTemplate(messageTemplate)
    +                .addPropertyNode(propertyName)
    +                .addBeanNode().inIterable().atKey(key)
    +                .addConstraintViolation();
    +    }
    +
    +    @Nullable
    +    private String escapeEl(@Nullable String s) {
    +        if (s == null || s.isEmpty()) {
    +            return s;
    +        }
    +
    +        final Matcher m = ESCAPE_PATTERN.matcher(s);
    +        final StringBuffer sb = new StringBuffer(s.length() + 16);
    +        while (m.find()) {
    +            m.appendReplacement(sb, "\\\\\\${");
    +        }
    +        m.appendTail(sb);
    +
    +        return sb.toString();
         }
     
         /**
    
  • dropwizard-validation/src/test/java/io/dropwizard/validation/SelfValidationTest.java+49 16 modified
    @@ -10,11 +10,11 @@
     import static org.assertj.core.api.Assertions.assertThat;
     
     public class SelfValidationTest {
    -
         private static final String FAILED = "failed";
     
         @SelfValidating
         public static class FailingExample {
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void validateFail(ViolationCollector col) {
                 col.addViolation(FAILED);
    @@ -23,6 +23,7 @@ public void validateFail(ViolationCollector col) {
     
         @SelfValidating
         public static class DirectContextExample {
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void validateFail(ViolationCollector col) {
                 col.getContext().buildConstraintViolationWithTemplate(FAILED).addConstraintViolation();
    @@ -51,34 +52,44 @@ public void validateFailAdditionalParameters(ViolationCollector col, int a) {
                 col.addViolation(FAILED);
             }
     
    +        @SuppressWarnings("unused")
             @SelfValidation
             public boolean validateFailReturn(ViolationCollector col) {
                 col.addViolation(FAILED);
                 return true;
             }
     
    +        @SuppressWarnings("unused")
             @SelfValidation
             private void validateFailPrivate(ViolationCollector col) {
                 col.addViolation(FAILED);
             }
         }
     
    -
         @SelfValidating
         public static class ComplexExample {
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void validateFail1(ViolationCollector col) {
                 col.addViolation(FAILED + "1");
             }
     
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void validateFail2(ViolationCollector col) {
    -            col.addViolation(FAILED + "2");
    +            col.addViolation("p2", FAILED);
             }
     
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void validateFail3(ViolationCollector col) {
    -            col.addViolation(FAILED + "3");
    +            col.addViolation("p", 3, FAILED);
    +        }
    +
    +        @SuppressWarnings("unused")
    +        @SelfValidation
    +        public void validateFail4(ViolationCollector col) {
    +            col.addViolation("p", "four", FAILED);
             }
     
             @SuppressWarnings("unused")
    @@ -91,42 +102,54 @@ public void validateCorrect(ViolationCollector col) {
         public static class NoValidations {
         }
     
    +    @SelfValidating
    +    public static class InjectionExample {
    +        @SuppressWarnings("unused")
    +        @SelfValidation
    +        public void validateFail(ViolationCollector col) {
    +            col.addViolation("${'value'}");
    +            col.addViolation("${'property'}", "${'value'}");
    +            col.addViolation("${'property'}", 1, "${'value'}");
    +            col.addViolation("${'property'}", "${'key'}", "${'value'}");
    +        }
    +    }
    +
         private final Validator validator = BaseValidator.newValidator();
     
         @Test
    -    public void failingExample() throws Exception {
    +    public void failingExample() {
             assertThat(ConstraintViolations.format(validator.validate(new FailingExample())))
                 .containsOnly(" " + FAILED);
         }
     
         @Test
    -    public void correctExample() throws Exception {
    +    public void correctExample() {
             assertThat(ConstraintViolations.format(validator.validate(new CorrectExample())))
                 .isEmpty();
         }
     
         @Test
    -    public void multipleTestingOfSameClass() throws Exception {
    +    public void multipleTestingOfSameClass() {
             assertThat(ConstraintViolations.format(validator.validate(new CorrectExample())))
    -            .isEmpty();
    +                .isEmpty();
             assertThat(ConstraintViolations.format(validator.validate(new CorrectExample())))
                 .isEmpty();
         }
     
         @Test
    -    public void testDirectContextUsage() throws Exception {
    +    public void testDirectContextUsage() {
             assertThat(ConstraintViolations.format(validator.validate(new DirectContextExample())))
                 .containsOnly(" " + FAILED);
         }
     
         @Test
    -    public void complexExample() throws Exception {
    +    public void complexExample() {
             assertThat(ConstraintViolations.format(validator.validate(new ComplexExample())))
    -            .containsOnly(
    -                " " + FAILED + "1",
    -                " " + FAILED + "2",
    -                " " + FAILED + "3"
    -            );
    +                .containsExactly(
    +                        " failed1",
    +                        "p2 failed",
    +                        "p[3] failed",
    +                        "p[four] failed");
         }
     
         @Test
    @@ -136,8 +159,18 @@ public void invalidExample() throws Exception {
         }
     
         @Test
    -    public void giveWarningIfNoValidationMethods() throws Exception {
    +    public void giveWarningIfNoValidationMethods() {
             assertThat(ConstraintViolations.format(validator.validate(new NoValidations())))
                 .isEmpty();
         }
    +
    +    @Test
    +    public void violationMessagesAreEscaped() {
    +        assertThat(ConstraintViolations.format(validator.validate(new InjectionExample()))).containsExactly(
    +                " ${'value'}",
    +                "${'property'} ${'value'}",
    +                "${'property'}[${'key'}] ${'value'}",
    +                "${'property'}[1] ${'value'}"
    +        );
    +    }
     }
    
d87d1e4f8e20

Escape EL expressions in ViolationCollector (#3157)

https://github.com/dropwizard/dropwizardJochen SchalandaFeb 20, 2020via ghsa
2 files changed · +197 91
  • dropwizard-validation/src/main/java/io/dropwizard/validation/selfvalidating/ViolationCollector.java+75 5 modified
    @@ -1,12 +1,16 @@
     package io.dropwizard.validation.selfvalidating;
     
    +import javax.annotation.Nullable;
     import javax.validation.ConstraintValidatorContext;
    +import java.util.regex.Matcher;
    +import java.util.regex.Pattern;
     
     /**
      * This class is a simple wrapper around the ConstraintValidatorContext of hibernate validation.
      * It collects all the violations of the SelfValidation methods of an object.
      */
     public class ViolationCollector {
    +    private static final Pattern ESCAPE_PATTERN = Pattern.compile("\\$\\{");
     
         private boolean violationOccurred = false;
         private ConstraintValidatorContext context;
    @@ -17,14 +21,80 @@ public ViolationCollector(ConstraintValidatorContext context) {
         }
     
         /**
    -     * Adds a new violation to this collector. This also sets violationOccurred to true.
    +     * Adds a new violation to this collector. This also sets {@code violationOccurred} to {@code true}.
          *
    -     * @param msg the message of the violation
    +     * @param message the message of the violation (any EL expression will be escaped and not parsed)
          */
    -    public void addViolation(String msg) {
    +    public void addViolation(String message) {
             violationOccurred = true;
    -        context.buildConstraintViolationWithTemplate(msg)
    -            .addConstraintViolation();
    +        String messageTemplate = escapeEl(message);
    +        context.buildConstraintViolationWithTemplate(messageTemplate)
    +                .addConstraintViolation();
    +    }
    +
    +    /**
    +     * Adds a new violation to this collector. This also sets {@code violationOccurred} to {@code true}.
    +     *
    +     * @param propertyName the name of the property
    +     * @param message      the message of the violation (any EL expression will be escaped and not parsed)
    +     * @since 2.0.2
    +     */
    +    public void addViolation(String propertyName, String message) {
    +        violationOccurred = true;
    +        String messageTemplate = escapeEl(message);
    +        context.buildConstraintViolationWithTemplate(messageTemplate)
    +                .addPropertyNode(propertyName)
    +                .addConstraintViolation();
    +    }
    +
    +    /**
    +     * Adds a new violation to this collector. This also sets {@code violationOccurred} to {@code true}.
    +     *
    +     * @param propertyName the name of the property with the violation
    +     * @param index        the index of the element with the violation
    +     * @param message      the message of the violation (any EL expression will be escaped and not parsed)
    +     * @since 2.0.2
    +     */
    +    public void addViolation(String propertyName, Integer index, String message) {
    +        violationOccurred = true;
    +        String messageTemplate = escapeEl(message);
    +        context.buildConstraintViolationWithTemplate(messageTemplate)
    +                .addPropertyNode(propertyName)
    +                .addBeanNode().inIterable().atIndex(index)
    +                .addConstraintViolation();
    +    }
    +
    +    /**
    +     * Adds a new violation to this collector. This also sets {@code violationOccurred} to {@code true}.
    +     *
    +     * @param propertyName the name of the property with the violation
    +     * @param key          the key of the element with the violation
    +     * @param message      the message of the violation (any EL expression will be escaped and not parsed)
    +     * @since 2.0.2
    +     */
    +    public void addViolation(String propertyName, String key, String message) {
    +        violationOccurred = true;
    +        String messageTemplate = escapeEl(message);
    +        context.buildConstraintViolationWithTemplate(messageTemplate)
    +                .addPropertyNode(propertyName)
    +                .addBeanNode().inIterable().atKey(key)
    +                .addConstraintViolation();
    +    }
    +
    +    @Nullable
    +    private String escapeEl(@Nullable String s) {
    +        if (s == null || s.isEmpty()) {
    +            return s;
    +        }
    +
    +        final Matcher m = ESCAPE_PATTERN.matcher(s);
    +        final StringBuffer sb = new StringBuffer(s.length() + 16);
    +        while (m.find()) {
    +            m.appendReplacement(sb, "\\\\\\${");
    +        }
    +        m.appendTail(sb);
    +
    +        return sb.toString();
         }
     
         /**
    
  • dropwizard-validation/src/test/java/io/dropwizard/validation/SelfValidationTest.java+122 86 modified
    @@ -1,64 +1,68 @@
     package io.dropwizard.validation;
     
    -import static org.assertj.core.api.Assertions.assertThat;
    -
    -import javax.annotation.concurrent.NotThreadSafe;
    -import javax.validation.Validator;
    -
    -import org.junit.jupiter.api.AfterEach;
    -import org.junit.jupiter.api.BeforeEach;
    -import org.junit.jupiter.api.Test;
    -
     import io.dropwizard.validation.selfvalidating.SelfValidating;
     import io.dropwizard.validation.selfvalidating.SelfValidation;
     import io.dropwizard.validation.selfvalidating.ViolationCollector;
    +import org.junit.jupiter.api.AfterEach;
    +import org.junit.jupiter.api.BeforeEach;
    +import org.junit.jupiter.api.Test;
     import uk.org.lidalia.slf4jext.Level;
     import uk.org.lidalia.slf4jtest.LoggingEvent;
     import uk.org.lidalia.slf4jtest.TestLoggerFactory;
     
    +import javax.annotation.concurrent.NotThreadSafe;
    +import javax.validation.Validator;
    +
    +import static org.assertj.core.api.Assertions.assertThat;
    +
     @NotThreadSafe
     public class SelfValidationTest {
     
         private static final String FAILED = "failed";
         private static final String FAILED_RESULT = " " + FAILED;
    -    
    -    @BeforeEach @AfterEach
    +
    +    @AfterEach
    +    @BeforeEach
         public void clearAllLoggers() {
             //this must be a clear all because the validation runs in other threads
             TestLoggerFactory.clearAll();
         }
     
         @SelfValidating
         public static class FailingExample {
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void validateFail(ViolationCollector col) {
                 col.addViolation(FAILED);
             }
         }
    -    
    +
         public static class SubclassExample extends FailingExample {
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void subValidateFail(ViolationCollector col) {
    -            col.addViolation(FAILED+"subclass");
    -        } 
    +            col.addViolation(FAILED + "subclass");
    +        }
         }
     
         @SelfValidating
         public static class AnnotatedSubclassExample extends FailingExample {
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void subValidateFail(ViolationCollector col) {
    -            col.addViolation(FAILED+"subclass");
    -        } 
    +            col.addViolation(FAILED + "subclass");
    +        }
         }
    -    
    +
         public static class OverridingExample extends FailingExample {
             @Override
             public void validateFail(ViolationCollector col) {
    -        } 
    +        }
         }
     
         @SelfValidating
         public static class DirectContextExample {
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void validateFail(ViolationCollector col) {
                 col.getContext().buildConstraintViolationWithTemplate(FAILED).addConstraintViolation();
    @@ -102,19 +106,28 @@ private void validateFailPrivate(ViolationCollector col) {
     
         @SelfValidating
         public static class ComplexExample {
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void validateFail1(ViolationCollector col) {
                 col.addViolation(FAILED + "1");
             }
     
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void validateFail2(ViolationCollector col) {
    -            col.addViolation(FAILED + "2");
    +            col.addViolation("p2", FAILED);
             }
     
    +        @SuppressWarnings("unused")
             @SelfValidation
             public void validateFail3(ViolationCollector col) {
    -            col.addViolation(FAILED + "3");
    +            col.addViolation("p", 3, FAILED);
    +        }
    +
    +        @SuppressWarnings("unused")
    +        @SelfValidation
    +        public void validateFail4(ViolationCollector col) {
    +            col.addViolation("p", "four", FAILED);
             }
     
             @SuppressWarnings("unused")
    @@ -127,121 +140,144 @@ public void validateCorrect(ViolationCollector col) {
         public static class NoValidations {
         }
     
    +    @SelfValidating
    +    public static class InjectionExample {
    +        @SuppressWarnings("unused")
    +        @SelfValidation
    +        public void validateFail(ViolationCollector col) {
    +            col.addViolation("${'value'}");
    +            col.addViolation("${'property'}", "${'value'}");
    +            col.addViolation("${'property'}", 1, "${'value'}");
    +            col.addViolation("${'property'}", "${'key'}", "${'value'}");
    +        }
    +    }
    +
         private final Validator validator = BaseValidator.newValidator();
     
         @Test
    -    public void failingExample() throws Exception {
    +    public void failingExample() {
             assertThat(ConstraintViolations.format(validator.validate(new FailingExample())))
    -            .containsExactlyInAnyOrder(FAILED_RESULT);
    +                .containsExactlyInAnyOrder(FAILED_RESULT);
             assertThat(TestLoggerFactory.getAllLoggingEvents())
    -            .isEmpty();
    +                .isEmpty();
         }
    -    
    +
         @Test
    -    public void subClassExample() throws Exception {
    +    public void subClassExample() {
             assertThat(ConstraintViolations.format(validator.validate(new SubclassExample())))
    -            .containsExactlyInAnyOrder(
    -                    FAILED_RESULT,
    -                    FAILED_RESULT+"subclass"
    -            );
    +                .containsExactlyInAnyOrder(
    +                        FAILED_RESULT,
    +                        FAILED_RESULT + "subclass"
    +                );
             assertThat(TestLoggerFactory.getAllLoggingEvents())
    -            .isEmpty();
    +                .isEmpty();
         }
    -    
    +
         @Test
    -    public void annotatedSubClassExample() throws Exception {
    +    public void annotatedSubClassExample() {
             assertThat(ConstraintViolations.format(validator.validate(new AnnotatedSubclassExample())))
    -            .containsExactlyInAnyOrder(
    -                    FAILED_RESULT,
    -                    FAILED_RESULT+"subclass"
    -            );
    +                .containsExactlyInAnyOrder(
    +                        FAILED_RESULT,
    +                        FAILED_RESULT + "subclass"
    +                );
             assertThat(TestLoggerFactory.getAllLoggingEvents())
    -            .isEmpty();
    +                .isEmpty();
         }
    -    
    +
         @Test
    -    public void overridingSubClassExample() throws Exception {
    +    public void overridingSubClassExample() {
             assertThat(ConstraintViolations.format(validator.validate(new OverridingExample())))
    -            .isEmpty();
    +                .isEmpty();
             assertThat(TestLoggerFactory.getAllLoggingEvents())
    -            .isEmpty();
    +                .isEmpty();
         }
     
         @Test
    -    public void correctExample() throws Exception {
    +    public void correctExample() {
             assertThat(ConstraintViolations.format(validator.validate(new CorrectExample())))
    -            .isEmpty();
    +                .isEmpty();
             assertThat(TestLoggerFactory.getAllLoggingEvents())
    -            .isEmpty();
    +                .isEmpty();
         }
     
         @Test
    -    public void multipleTestingOfSameClass() throws Exception {
    +    public void multipleTestingOfSameClass() {
             assertThat(ConstraintViolations.format(validator.validate(new CorrectExample())))
    -            .isEmpty();
    +                .isEmpty();
             assertThat(ConstraintViolations.format(validator.validate(new CorrectExample())))
    -            .isEmpty();
    +                .isEmpty();
             assertThat(TestLoggerFactory.getAllLoggingEvents())
    -            .isEmpty();
    +                .isEmpty();
         }
     
         @Test
    -    public void testDirectContextUsage() throws Exception {
    +    public void testDirectContextUsage() {
             assertThat(ConstraintViolations.format(validator.validate(new DirectContextExample())))
    -            .containsExactlyInAnyOrder(FAILED_RESULT);
    +                .containsExactlyInAnyOrder(FAILED_RESULT);
             assertThat(TestLoggerFactory.getAllLoggingEvents())
    -            .isEmpty();
    +                .isEmpty();
         }
     
         @Test
    -    public void complexExample() throws Exception {
    +    public void complexExample() {
             assertThat(ConstraintViolations.format(validator.validate(new ComplexExample())))
    -            .containsExactlyInAnyOrder(
    -                FAILED_RESULT + "1",
    -                FAILED_RESULT + "2",
    -                FAILED_RESULT + "3"
    -            );
    +                .containsExactly(
    +                        " failed1",
    +                        "p2 failed",
    +                        "p[3] failed",
    +                        "p[four] failed");
             assertThat(TestLoggerFactory.getAllLoggingEvents())
    -            .isEmpty();
    +                .isEmpty();
         }
     
         @Test
         public void invalidExample() throws Exception {
             assertThat(ConstraintViolations.format(validator.validate(new InvalidExample())))
    -            .isEmpty();
    +                .isEmpty();
             assertThat(TestLoggerFactory.getAllLoggingEvents())
    -            .containsExactlyInAnyOrder(
    -                    new LoggingEvent(
    -                            Level.ERROR, 
    -                            "The method {} is annotated with @SelfValidation but does not have a single parameter of type {}",
    -                            InvalidExample.class.getMethod("validateFailAdditionalParameters", ViolationCollector.class, int.class),
    -                            ViolationCollector.class
    -                    ),
    -                    new LoggingEvent(
    -                            Level.ERROR, 
    -                            "The method {} is annotated with @SelfValidation but does not return void. It is ignored",
    -                            InvalidExample.class.getMethod("validateFailReturn", ViolationCollector.class)
    -                    ),
    -                    new LoggingEvent(
    -                            Level.ERROR, 
    -                            "The method {} is annotated with @SelfValidation but is not public",
    -                            InvalidExample.class.getDeclaredMethod("validateFailPrivate", ViolationCollector.class)
    -                    )
    -            );
    +                .containsExactlyInAnyOrder(
    +                        new LoggingEvent(
    +                                Level.ERROR,
    +                                "The method {} is annotated with @SelfValidation but does not have a single parameter of type {}",
    +                                InvalidExample.class.getMethod("validateFailAdditionalParameters", ViolationCollector.class, int.class),
    +                                ViolationCollector.class
    +                        ),
    +                        new LoggingEvent(
    +                                Level.ERROR,
    +                                "The method {} is annotated with @SelfValidation but does not return void. It is ignored",
    +                                InvalidExample.class.getMethod("validateFailReturn", ViolationCollector.class)
    +                        ),
    +                        new LoggingEvent(
    +                                Level.ERROR,
    +                                "The method {} is annotated with @SelfValidation but is not public",
    +                                InvalidExample.class.getDeclaredMethod("validateFailPrivate", ViolationCollector.class)
    +                        )
    +                );
         }
     
         @Test
    -    public void giveWarningIfNoValidationMethods() throws Exception {
    +    public void giveWarningIfNoValidationMethods() {
             assertThat(ConstraintViolations.format(validator.validate(new NoValidations())))
    -            .isEmpty();
    +                .isEmpty();
             assertThat(TestLoggerFactory.getAllLoggingEvents())
    -        .containsExactlyInAnyOrder(
    -                new LoggingEvent(
    -                        Level.WARN, 
    -                        "The class {} is annotated with @SelfValidating but contains no valid methods that are annotated with @SelfValidation",
    -                        NoValidations.class
    -                )
    -                
    +                .containsExactlyInAnyOrder(
    +                        new LoggingEvent(
    +                                Level.WARN,
    +                                "The class {} is annotated with @SelfValidating but contains no valid methods that are annotated with @SelfValidation",
    +                                NoValidations.class
    +                        )
    +
    +                );
    +    }
    +
    +    @Test
    +    public void violationMessagesAreEscaped() {
    +        assertThat(ConstraintViolations.format(validator.validate(new InjectionExample()))).containsExactly(
    +                " ${'value'}",
    +                "${'property'} ${'value'}",
    +                "${'property'}[${'key'}] ${'value'}",
    +                "${'property'}[1] ${'value'}"
             );
    +        assertThat(TestLoggerFactory.getAllLoggingEvents()).isEmpty();
         }
     }
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

11

News mentions

0

No linked articles in our index yet.