Template Injection in BrowserUp Proxy
Description
BrowserUp Proxy allows you to manipulate HTTP requests and responses, capture HTTP content, and export performance data as a HAR file. BrowserUp Proxy works well as a standalone proxy server, but it is especially useful when embedded in Selenium tests. A Server-Side Template Injection was identified in BrowserUp Proxy enabling attackers to inject arbitrary Java EL expressions, leading to unauthenticated Remote Code Execution (RCE) vulnerability. This has been patched in version 2.1.2.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
com.browserup:browserup-proxyMaven | < 2.1.2 | 2.1.2 |
Affected products
1- Range: < 2.1.2
Patches
14b38e7a3e209Fix Critical Java EL Injection RCE vulnerability from GHSL-2020-213
5 files changed · +52 −9
browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/LongPositiveConstraint.java+6 −3 modified@@ -8,6 +8,7 @@ import javax.validation.ConstraintValidatorContext; import javax.validation.Payload; +import com.browserup.bup.rest.validation.util.MessageSanitizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,12 +42,14 @@ public boolean isValid(String value, ConstraintValidatorContext context) { longValue = Long.parseLong(value); } catch (NumberFormatException ex) { failed = true; - errorMessage = String.format("Invalid integer value: '%s'", value); + String escapedValue = MessageSanitizer.escape(value); + errorMessage = String.format("Invalid integer value: '%s'", escapedValue); } if (!failed && longValue < 0) { failed = true; - errorMessage = String.format("Expected positive integer value, got: '%s'", value); + String escapedValue = MessageSanitizer.escape(value); + errorMessage = String.format("Expected positive integer value, got: '%s'", escapedValue); } if (!failed) { @@ -59,4 +62,4 @@ public boolean isValid(String value, ConstraintValidatorContext context) { return false; } } -} \ No newline at end of file +}
browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/NotBlankConstraint.java+5 −2 modified@@ -8,6 +8,7 @@ import javax.validation.ConstraintValidatorContext; import javax.validation.Payload; +import com.browserup.bup.rest.validation.util.MessageSanitizer; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,11 +37,13 @@ public boolean isValid(Object value, ConstraintValidatorContext context) { if (value != null && StringUtils.isNotEmpty(String.valueOf(value))) { return true; } - String errorMessage = String.format("Expected not empty value, got '%s'", value); + + String escapedValue = MessageSanitizer.escape(value == null ? null : value.toString()); + String errorMessage = String.format("Expected not empty value, got '%s'", escapedValue); LOG.warn(errorMessage); context.buildConstraintViolationWithTemplate(errorMessage).addConstraintViolation(); return false; } } -} \ No newline at end of file +}
browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/PatternConstraint.java+4 −2 modified@@ -9,6 +9,7 @@ import javax.validation.ConstraintValidatorContext; import javax.validation.Payload; +import com.browserup.bup.rest.validation.util.MessageSanitizer; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,12 +43,13 @@ public boolean isValid(String value, ConstraintValidatorContext context) { Pattern.compile(value); return true; } catch (Exception ex) { - String errorMessage = String.format("URL parameter '%s' is not a valid regexp", value); + String escapedValue = MessageSanitizer.escape(value); + String errorMessage = String.format("URL parameter '%s' is not a valid regexp", escapedValue); LOG.warn(errorMessage); context.buildConstraintViolationWithTemplate(errorMessage).addConstraintViolation(); } return false; } } -} \ No newline at end of file +}
browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/PortWithExistingProxyConstraint.java+4 −2 modified@@ -11,6 +11,7 @@ import com.browserup.bup.proxy.ProxyManager; +import com.browserup.bup.rest.validation.util.MessageSanitizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,11 +48,12 @@ public boolean isValid(Integer value, ConstraintValidatorContext context) { return true; } - String errorMessage = String.format("No proxy server found for specified port %d", value); + String escapedValue = MessageSanitizer.escape(value.toString()); + String errorMessage = String.format("No proxy server found for specified port %s", escapedValue); LOG.warn(errorMessage); context.buildConstraintViolationWithTemplate(errorMessage).addPropertyNode(PARAM_NAME).addConstraintViolation(); return false; } } -} \ No newline at end of file +}
browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/util/MessageSanitizer.java+33 −0 added@@ -0,0 +1,33 @@ +package com.browserup.bup.rest.validation.util; +/* + * Modifications Copyright (c) 2019 BrowserUp, Inc. + * Original from: + * https://github.com/hibernate/hibernate-validator/blob/master/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/util/InterpolationHelper.java + */ +/* + * License: Apache License, Version 2.0 + * See the license file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>. + */ + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MessageSanitizer { + + public static final char BEGIN_CHAR = '{'; + public static final char END_CHAR = '}'; + public static final char EL_DESIGNATOR = '$'; + public static final char ESCAPE_CHARACTER = '\\'; + + private static final Pattern ESCAPE_PATTERN = Pattern.compile( "([\\" + ESCAPE_CHARACTER + BEGIN_CHAR + END_CHAR + EL_DESIGNATOR + "])" ); + + private MessageSanitizer() { + } + + public static String escape(String message) { + if ( message == null ) { + return null; + } + return ESCAPE_PATTERN.matcher( message ).replaceAll( Matcher.quoteReplacement( String.valueOf( ESCAPE_CHARACTER ) ) + "$1" ); + } +}
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-wmfg-55f9-j8hqghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-26282ghsaADVISORY
- github.com/browserup/browserup-proxy/commit/4b38e7a3e20917e5c3329d0d4e9590bed9d578abghsax_refsource_MISCWEB
- github.com/browserup/browserup-proxy/releases/tag/v2.1.2ghsax_refsource_MISCWEB
- github.com/browserup/browserup-proxy/security/advisories/GHSA-wmfg-55f9-j8hqghsax_refsource_CONFIRMWEB
- securitylab.github.com/research/bean-validation-RCEghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.