Summary
A bug in Hibernate Validator’s interpolation of constraint error messages enables invalid EL expressions to be evaluated as if they were valid.
This bug enables attackers to bypass input sanitation (escaping, stripping) controls that developers may have put in place when handling user-controlled data in error messages.
Product
Hibernate Validator
Tested Version
6.1.2.Final
Details
Incorrect EL expression tokenization (GHSL-2020-020, CVE-2020-10693)
The ConstraintValidatorContext
documentation specifies that developers should be very careful when integrating user input into a custom message template as it will be interpreted by the Expression Language engine, which may allow attackers to run arbitrary Java code.
Several applications attempt to prevent such EL injections by replacing the EL opening delimiter ${
with just {
e.g.:
public String replaceElDelimiter(final String value) {
if (value != null) {
return value.replaceAll("\\$+\\{", "{");
}
return null;
}
This is seemingly a secure way to prevent injection attacks since all occurrences of ${
will be replaced with {
, and since the regex matches repeating $
it will also fix more intricate injection attempts that send e.g. $${
in an attempt to arrive at the ${
delimiter to achieve EL execution.
However, a bug in the Hibernate message interpolation parser (org.hibernate.validator.internal.engine.messageinterpolation.parser.TokenCollector), allows attackers to bypass this protection with a payload such as FOO $\A{payload}
. The reason is the following:
- When the parser encounters
$
we move tohandleELDesignator
and due totokenCollector.getInterpolationType().equals(InterpolationTermType.EL)
we skip the character and move toELState
state. - When the parser encounters
\
in theELState
, we skip the character and move toEscapedState
- When the parser encounters
A
in theEscapedState
, we append it to the current token (FOO A
) and move back toELState
- When the parser encounters
{
in theELState
, we terminate the current token, which will remain asFOO A
, and then we create a new empty token and append${
to it, so it is basically replacing{
with${
and then it marks the new token as an EL token and moves to theInterpolationTermState
Impact
This issue may lead to mitigation bypasses that allow for remote code execution in affected applications.
CVE
- CVE-2020-10693
Coordinated Disclosure Timeline
- 02/05/2020: Report sent to Vendor
- 02/05/2020: Assigned INC1163499 internal ID
- 03/06/2020: RedHat asks for reproducer PoC
- 03/10/2020: Sent PoC to RedHat
- 03/13/2020: RedHat asks for EL payload to run arbitrary commands
- 03/13/2020: Sent arbitrary command execution payload to RedHat
- 04/14/2020: Issue is assigned CVE-2020-10693 and moved to EMBARGOED status
- 05/05/2020: Embargo is lifted
- 05/11/2020: Public Advisory
Supporting Resources
- https://access.redhat.com/security/cve/CVE-2020-10693
- https://bugzilla.redhat.com/show_bug.cgi?id=1805501
Credit
This issue was discovered and reported by GHSL team member @pwntester (Alvaro Muñoz).
Contact
You can contact the GHSL team at securitylab@github.com
, please include the GHSL-2020-020
in any communication regarding this issue.