Skip to main content
VulnerabilityPublished

Org.jdbi:jdbi3 freemarker: jdbi3-freemarker Vulnerable to Improper Neutralization of Special Elements Used in

Affects org.jdbi:jdbi3-freemarkerSource GCVE Database

0

CVSS 7.5 High : upgrade to 3.53.0 soon.

Data as of 27 Oct 2026, 00:07 UTC

CVSS 4.0 base score
7.5High
How severe the flaw is on the 0–10 CVSS scale.
Patch
Available – fixed in 3.53.0
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

What to do

Upgrade org.jdbi:jdbi3-freemarker to 3.53.0.

Affected software

ProductAffectedFixed in
Mavenorg.jdbi:jdbi3-freemarkerAffected
  • <3.53.0
Fixed in
  • 3.53.0

Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.

Description

# Summary **Description** An Improper Neutralization of Special Elements Used in a Template Engine (CWE-1336) vulnerability in Jdbi allows arbitrary command execution when an application using `jdbi3-freemarker` permits attacker-influenced text to reach `FreemarkerEngine.parse()` as template source. This affects `org.jdbi:jdbi3-freemarker` through version 3.52.1. The developer opts into FreeMarker-backed SQL templating, but does not explicitly opt into reflective Java class loading from template source. Jdbi’s FreeMarker integration should not expose unrestricted Java class instantiation by default in a SQL templating module. While the SQL injection risk is acknowledged, Jdbi’s documentation explicitly supports and demonstrates dynamic SQL templating through defined attributes, including substitution of non-bindable SQL elements such `ORDER BY` columns. ## Details Jdbi constructs the underlying `freemarker.template.Configuration` with `DEFAULT_INCOMPATIBLE_IMPROVEMENTS` and never installs a `TemplateClassResolver`, so Freemarker's legacy `UNRESTRICTED_RESOLVER` remains active and the `?new` built-in can instantiate arbitrary classes, including `freemarker.template.utility.Execute`. Two `Configuration` instances are constructed in the module, neither of which is hardened: ```java // freemarker/src/main/java/org/jdbi/v3/freemarker/FreemarkerConfig.java public FreemarkerConfig() { freemarkerConfiguration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); freemarkerConfiguration.setTemplateLoader(new ClassTemplateLoader(selectClassLoader(), "/")); freemarkerConfiguration.setNumberFormat("computer"); } ``` ```java // freemarker/src/main/java/org/jdbi/v3/freemarker/FreemarkerSqlLocator.java static { Configuration c = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); c.setTemplateLoader(new ClassTemplateLoader(selectClassLoader(), "/")); c.setNumberFormat("computer"); CONFIGURATION = c; } ``` The locator's `CONFIGURATION` is initialized once at class load and used by the deprecated static `findTemplate(Class, String)`. It cannot be replaced via `FreemarkerConfig#setFreemarkerConfiguration(...)`, so any fix must land in both call sites. The sink is `FreemarkerEngine.parse()`, which constructs a `Template` from the raw SQL string and renders it against `ctx.getAttributes()`: ```java // freemarker/src/main/java/org/jdbi/v3/freemarker/FreemarkerEngine.java Template template = new Template(null, sqlTemplate, config.get(FreemarkerConfig.class).getFreemarkerConfiguration()); return Optional.of(ctx -> { StringWriter writer = new StringWriter(); template.process(ctx.getAttributes(), writer); return writer.toString(); }); ``` Freemarker is the only built-in engine whose parse path provides reflective class loading by default. ## Impact This impacts all `jdbi3-freemarker` releases through 3.52.1. Exploitation requires that an application depend on `jdbi3-freemarker`and allow request-derived text to flow into a SQL template body passed to `Handle.createQuery(String)`, `createUpdate(String)`, `createCall(String)`, `createScript(String)`, or `Batch.add(String)`, or into a defined attribute that the template subsequently re-evaluates with `?eval` or `?interpret`. An application that allows attacker-influenced text to become FreeMarker template source, either directly through a SQL string passed to Jdbi or indirectly through a trusted template that applies `?eval` / `?interpret` to an attacker-influenced defined attribute, can become an RCE sink in the application JVM. ## Proposed Patch The injection surface is the `Configuration` constructed by Jdbi on the application's behalf without a class-resolver policy. `FreemarkerConfig` and `FreemarkerSqlLocator`'s static initializer should not allow SQL templates to instantiate arbitrary Java classes by default. Callers that genuinely need reflective `?new` can override the `Configuration` via `FreemarkerConfig#setFreemarkerConfiguration(...)`. The static `CONFIGURATION` field cannot be reconfigured by application code at runtime, so a fix limited to `FreemarkerConfig` leaves the legacy locator path exploitable. ```java import freemarker.core.TemplateClassResolver; // FreemarkerConfig.java public FreemarkerConfig() { freemarkerConfiguration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); freemarkerConfiguration.setTemplateLoader(new ClassTemplateLoader(selectClassLoader(), "/")); freemarkerConfiguration.setNumberFormat("computer"); freemarkerConfiguration.setNewBuiltinClassResolver(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER); } // FreemarkerSqlLocator.java static { Configuration c = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); c.setTemplateLoader(new ClassTemplateLoader(selectClassLoader(), "/")); c.setNumberFormat("computer"); c.setNewBuiltinClassResolver(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER);

References

Community reviews

Loading reviews…