May 6, 2026·5 min read·4 visits
Jdbi's FreeMarker module (<= 3.52.1) is vulnerable to RCE due to an unrestricted template class resolver. Attackers can leverage the `?new` directive to execute OS commands if user input reaches the template engine. Upgrading to 3.53.0 resolves the issue.
The `jdbi3-freemarker` module in the Jdbi library contains an insecure default configuration that allows Remote Code Execution (RCE). The FreeMarker template engine is initialized without a restrictive class resolver, permitting attackers to execute arbitrary system commands via the `?new` directive when application input is unsafely concatenated into SQL templates. This vulnerability affects all versions up to 3.52.1 and is resolved in version 3.53.0.
The org.jdbi:jdbi3-freemarker package provides integration between the Jdbi SQL execution library and the FreeMarker template engine. This integration allows developers to use FreeMarker syntax to dynamically generate SQL queries. A critical vulnerability exists in how Jdbi initializes the FreeMarker configuration, leading to Improper Neutralization of Special Elements Used in a Template Engine (CWE-1336).
By default, the FreeMarker engine is initialized without specific restrictions on class instantiation. If an application permits attacker-controlled input to be concatenated or interpolated into a SQL template before evaluation, an attacker can inject malicious FreeMarker directives. The vulnerability fundamentally relies on the unsafe handling of input prior to template processing, combined with an insecure engine configuration.
The impact of successful exploitation is unauthenticated Remote Code Execution (RCE). An attacker can leverage built-in FreeMarker functionality to instantiate arbitrary Java classes present on the classpath. This directly leads to the execution of operating system commands under the security context of the Java application.
This vulnerability impacts all versions of org.jdbi:jdbi3-freemarker up to and including 3.52.1. The maintainers addressed the issue in version 3.53.0 by enforcing a secure default configuration that restricts class resolution capabilities.
The root cause lies in the initialization parameters of the freemarker.template.Configuration object within the Jdbi module. Specifically, two classes—FreemarkerConfig.java and FreemarkerSqlLocator.java—instantiate the FreeMarker configuration without explicitly defining a TemplateClassResolver.
When FreeMarker is initialized without a custom resolver, it defaults to using UNRESTRICTED_RESOLVER. This default resolver permits the ?new built-in directive to instantiate any Java class that exposes a public constructor. While intended for advanced templating logic, this feature poses a severe security risk when applied to untrusted input.
An attacker exploiting this configuration typically targets the freemarker.template.utility.Execute class. This utility class is included with FreeMarker and provides a mechanism to execute underlying operating system commands and return the standard output. Because the UNRESTRICTED_RESOLVER allows its instantiation, the system is exposed to command execution.
The vulnerability is triggered only when application code directly embeds user input into the template string. Safe usage of Jdbi involves passing user input as bind parameters rather than concatenating strings to form the template body.
Exploitation requires the attacker to identify an application endpoint where user input is unsafely integrated into a Jdbi SQL query evaluated by FreeMarker. The injection vector typically occurs in methods such as Handle.createQuery(String), createUpdate(String), createCall(String), createScript(String), or Batch.add(String).
The attacker constructs a payload utilizing the FreeMarker assignment directive (<#assign ...>) and the ?new() built-in. The payload instantiates the freemarker.template.utility.Execute class and subsequently calls it with the desired shell command as an argument.
# Standard FreeMarker execution payload
<#assign ex="freemarker.template.utility.Execute"?new()>${ex("touch /tmp/jdbi-pwned")}A vulnerable implementation pattern involves extracting input from an HTTP request and embedding it directly into the SQL statement string. In the following example, the q parameter is concatenated directly into the template.
// Vulnerable application setup
Jdbi jdbi = Jdbi.create("jdbc:h2:mem:poc");
jdbi.getConfig(SqlStatements.class).setTemplateEngine(FreemarkerEngine.instance());
// Vulnerable endpoint parsing unsanitized input
http.createContext("/search", ex -> {
String q = parseQuery(ex.getRequestURI().getRawQuery()).getOrDefault("q", "");
// ATTACKER INPUT concatenated into the SQL template string
String sql = "select email from users where email like '%" + q + "%'";
jdbi.withHandle(h -> h.createQuery(sql).mapTo(String.class).list());
});The attacker executes the exploit by sending the crafted payload to the vulnerable endpoint via an HTTP request. The application concatenates the payload into the sql string, passes it to FreeMarker, and inadvertently executes the touch command on the host system.
The exploitation of this vulnerability results in arbitrary command execution on the host server. The commands execute with the privileges of the JVM process running the application. This grants the attacker the ability to read arbitrary files, modify data, establish persistence, and pivot to internal network segments.
The CVSS v4.0 vector for this vulnerability is CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N, producing a base score of 7.7 (High). The Attack Requirements (AT:P) metric is present because exploitation relies on the application developer implementing an unsafe string concatenation pattern. The Privileges Required (PR:H) metric suggests that in many enterprise applications, manipulating the specific inputs that reach the SQL templating engine requires an authenticated session.
The impact on confidentiality, integrity, and availability is rated as High. Attackers can extract environment variables, database credentials, and application source code. They can modify critical business data or disrupt service operations by terminating processes or corrupting file systems.
Because the FreeMarker execution context operates outside the bounds of the application's intended SQL interaction, standard database access controls provide no protection against the OS-level commands executed via this vector.
The primary mitigation is upgrading the org.jdbi:jdbi3-freemarker dependency to version 3.53.0 or later. This version addresses the root cause by hardening the default FreeMarker configuration to prevent arbitrary class instantiation.
The patch implements a secure configuration policy by explicitly overriding the default class resolver. The Jdbi maintainers configured the FreeMarker engine to use TemplateClassResolver.ALLOWS_NOTHING_RESOLVER. This effectively neuters the ?new directive, preventing the instantiation of classes such as freemarker.template.utility.Execute.
import freemarker.core.TemplateClassResolver;
// Patch snippet demonstrating secure configuration initialization
freemarkerConfiguration.setNewBuiltinClassResolver(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER);If developers rely on the ?new directive for legitimate application functionality, they must explicitly opt back into a more permissive configuration. This is achieved by manually invoking FreemarkerConfig#setFreemarkerConfiguration(...) with a custom resolver. However, doing so reintroduces security risks unless carefully controlled.
In addition to upgrading the library, organizations must audit application code to eliminate unsafe string concatenation in SQL queries. Input should always be passed using Jdbi's parameter binding mechanisms (bind, bindBean, etc.) rather than directly modifying the template structure.
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
jdbi3-freemarker Jdbi | <= 3.52.1 | 3.53.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1336 |
| Attack Vector | Network |
| CVSS Score | 7.7 |
| Impact | Remote Code Execution (RCE) |
| Exploit Status | Proof of Concept Available |
| Affected Component | jdbi3-freemarker Template Initialization |
Improper Neutralization of Special Elements Used in a Template Engine