Skip to main content
Vulnerability Database/CVE-2026-94109

CVE-2026-94109: openEQUELLA Template Injection RCE Vulnerability

CVE-2026-94109 is an authenticated server-side template injection vulnerability in openEQUELLA that enables remote code execution. Any authenticated user can exploit this flaw to run malicious code. This article covers technical details, affected versions, impact assessment, and mitigation strategies.

Published:

CVE-2026-94109 Overview

CVE-2026-94109 is an authenticated stored server-side template injection (SSTI) vulnerability in openEQUELLA versions before 2026.1.0. The flaw resides in FreemarkerPortletRenderer.renderHtml(), where the markup field of a stored portlet configuration is passed directly to custFactory.createResult() without a TemplateClassResolver restriction or FreeMarker sandboxing in BasicConfiguration. Any authenticated non-guest user can store a malicious FreeMarker payload via a POST request to the RemotePortletService invoker endpoint. When any user renders a dashboard containing the affected portlet, the payload executes in the application server process context, achieving remote code execution. The issue is categorized under CWE-1336 (Improper Neutralization of Special Elements Used in a Template Engine).

Critical Impact

Any authenticated non-guest user can achieve remote code execution on the openEQUELLA application server by storing a malicious FreeMarker template that executes when a victim renders the dashboard.

Affected Products

  • openEQUELLA versions prior to 2026.1.0
  • Deployments exposing the RemotePortletService invoker endpoint to authenticated users
  • Any dashboard configuration allowing portlet markup persistence

Discovery Timeline

  • 2026-09-20 - CVE-2026-94109 published to NVD
  • 2026-09-24 - Last updated in NVD database

Technical Details for CVE-2026-94109

Vulnerability Analysis

The vulnerability exists in openEQUELLA's FreeMarker portlet rendering pipeline. The BasicConfiguration class extends FreeMarker's Configuration but omits any TemplateClassResolver restriction. This leaves dangerous built-ins such as ?new and freemarker.template.utility.Execute fully reachable at template evaluation time. When FreemarkerPortletRenderer.renderHtml() invokes custFactory.createResult(), the persisted markup string from the portlet is compiled and executed as a FreeMarker template.

Because the portlet's markup field is user-controlled and stored, the attack is second-order. An authenticated user submits the payload once through the RemotePortletService invoker endpoint. Any subsequent dashboard render, including by higher-privileged users, triggers execution in the application server JVM context.

Root Cause

The root cause is missing template engine hardening. FreeMarker ships with sandboxing primitives such as TemplateClassResolver.SAFER_RESOLVER, but BasicConfiguration did not apply them. Combined with unvalidated storage of user-supplied template markup, this exposes the full FreeMarker built-in surface to attackers.

Attack Vector

An attacker with any authenticated non-guest account issues a POST request to the RemotePortletService invoker endpoint containing a FreeMarker payload in the portlet's markup field. The payload is stored server-side. When a user loads a dashboard that includes the malicious portlet, the template engine evaluates built-ins like freemarker.template.utility.Execute?new()("cmd"), executing arbitrary operating system commands under the openEQUELLA service account.

java
// Security patch: Source/Plugins/Core/com.equella.core/src/com/tle/web/freemarker/BasicConfiguration.java
// OEQ-3000 - fix(security): lock down FreeMarker to prevent SSTI/RCE
 import com.tle.core.guice.Bind;
 import com.tle.web.DebugSettings;
 import freemarker.cache.NullCacheStorage;
+import freemarker.core.TemplateClassResolver;
 import freemarker.template.Configuration;
 import javax.inject.Singleton;

-@SuppressWarnings("nls")
 @Bind
 @Singleton
 public class BasicConfiguration extends Configuration {

Source: GitHub Commit d6e165af

Detection Methods for CVE-2026-94109

Indicators of Compromise

  • POST requests to the RemotePortletService invoker endpoint containing FreeMarker syntax such as <#assign, ?new, or freemarker.template.utility.Execute in the markup field.
  • Unexpected child processes spawned by the openEQUELLA application server JVM, particularly shells (sh, bash, cmd.exe) or reconnaissance binaries.
  • Newly created or modified portlet configurations authored by low-privilege accounts.
  • Outbound network connections initiated by the application server process to attacker-controlled infrastructure.

Detection Strategies

  • Inspect application and web server access logs for POST bodies to portlet service endpoints containing FreeMarker directives or Java class references.
  • Monitor the openEQUELLA JVM for anomalous process lineage using endpoint telemetry.
  • Audit stored portlet markup fields in the openEQUELLA database for FreeMarker built-ins that reference Execute, ObjectConstructor, or ?new.

Monitoring Recommendations

  • Enable verbose request logging on the RemotePortletService endpoint and forward to a centralized analytics platform.
  • Alert on child process creation from the openEQUELLA Java process using EDR behavioral rules.
  • Track dashboard render events tied to newly created portlets and correlate with the authoring user's privilege level.

How to Mitigate CVE-2026-94109

Immediate Actions Required

  • Upgrade openEQUELLA to version 2026.1.0 or later, which applies the TemplateClassResolver restriction in BasicConfiguration.
  • Review all stored portlets and remove any containing suspicious FreeMarker directives or references to freemarker.template.utility.Execute.
  • Rotate credentials for any accounts that may have been used to author malicious portlets and audit privileged session activity.

Patch Information

The fix is delivered in openEQUELLA Release 2026.1.0. The corresponding source change is tracked in GitHub Commit d6e165af under ticket OEQ-3000. Additional analysis is available in the VulnCheck Advisory on SSTI and the Evan Lat Blog Post.

Workarounds

  • Restrict access to the RemotePortletService invoker endpoint via network ACLs or reverse-proxy rules until patching is complete.
  • Limit portlet creation and editing rights to trusted administrators only.
  • Deploy a web application firewall rule to block request bodies containing FreeMarker built-ins such as ?new and freemarker.template.utility.Execute against portlet service paths.
bash
# Example WAF rule (ModSecurity) to block FreeMarker SSTI payloads to portlet endpoints
SecRule REQUEST_URI "@contains RemotePortletService" \
  "phase:2,deny,status:403,id:1094109,\
   chain,msg:'Potential FreeMarker SSTI (CVE-2026-94109)'"
  SecRule REQUEST_BODY "@rx (freemarker\.template\.utility\.Execute|\?new\(\))" "t:none,t:lowercase"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.