This vulnerability was described publicly as an SQL injection, but in reality it is a template injection.
The product contains a class named TemplateUtils, which is responsible for expression handling.
User-supplied expressions are rendered via the render method:

The template-parameter rendering method is renderParameter4Tpl, which keeps calling another render method. At the beginning it creates a new Calculator:

In the middle, evalRenderAction specifies a RenderAction. The other details are not that important; keep following the flow:

In the final renderTpl, we see the expression parsing logic: it parses via ParameterProvider.PARAMETERPATTERN and extracts the content inside the expression:


After parsing, it extracts the content inside ${} and passes it into the RenderAction (the one passed earlier) for rendering:


So var2.render is actually the earlier evalRenderAction:

Going deeper, it reaches evalString. Here it converts the input into an Expression:

Following this eval, we hit another eval — this is on the earlier Calculator:

Then it calls the next eval, which is the expression’s own eval. In practice this is RelationExpression, whose parent is BinaryExpression:

Next it evaluates another Node. This eval uses an index-based check: it actually retrieves the content on the right side of =. If it’s a function call, it becomes FunctionCall:

FunctionCall.eval calls resolveMethod, which is the key part of this vulnerability:

resolveMethod eventually resolves a namespace and calls getMethod:



At the function-dispatch point (where the vulnerability happens), the implementation of getMethod in DefaultNameSpace uses attacker-controlled input to load classes:

In practice it calls into com.fr.function.xxx. That package contains many functions. After resolving it, the engine continues to evaluate the expression via evalExpression:


Some reports online call this “SQL injection.” If you look at the SQL class… it’s pretty self-explanatory:


Entry point:

In practice this has a lot of flexibility; you don’t necessarily have to use SQL-style payloads for PoC/detection.
Now included in the “premium detection package”: