OpenMRS Module Upload Vulnerable to Path Traversal (Zip Slip)
Affected Versions
version ≤ 2.7.8 (latest version at time of disclosure)
https://github.com/openmrs/openmrs-core
Impact
The endpoint POST /openmrs/ws/rest/v1/module is vulnerable to a path traversal (Zip Slip) attack. An authenticated attacker can upload a crafted .omod archive containing ZIP entries with directory traversal sequences. Upon automatic extraction by the server, the incomplete path validation in WebModuleUtil.startModule() fails to prevent entries such as web/module/../../../../malicious.jsp from being written outside the intended module directory. If the traversal target falls within the web application root (e.g., /usr/local/tomcat/webapps/openmrs/), the attacker achieves arbitrary file write and subsequent Remote Code Execution.
Notably, other extraction methods in the same codebase (ModuleUtil.expandJar(), TestInstallUtil.addZippedTestModules()) are properly protected with normalize().startsWith() checks — this vulnerability is an oversight where the same fix was not applied.
Furthermore, the module.allow_web_admin runtime property, which is intended to restrict administrators from managing modules via the web interface, only gates the Legacy UI controller entry point. The REST API endpoint POST /openmrs/ws/rest/v1/module does not check this property, allowing this restriction to be fully bypassed.
Steps to Reproduce
- Construct a malicious
.omodfile (which is a ZIP/JAR archive) containing a ZIP entry with a path traversal payload in its entry name, such asweb/module/../../../../<target_filename>. Upload this file toPOST /openmrs/ws/rest/v1/modulewith valid admin credentials via Basic Auth.
- The server parses and loads the module. During
WebModuleUtil.startModule(), entries underweb/module/are automatically extracted. The existing checkPaths.get(name).startsWith("..")only blocks entries beginning with.., so an entry starting withweb/module/passes the check. The../sequences in the remaining path cause the file to be written outside the intendedWEB-INF/view/module/directory — for example, into the web application root at/usr/local/tomcat/webapps/openmrs/.
- The traversed file is now accessible under the web application root. If the written file is a JSP script, accessing it via the browser triggers server-side execution, achieving RCE.
Root Cause Analysis
The vulnerability exists in WebModuleUtil.startModule() (web/src/main/java/org/openmrs/module/web/WebModuleUtil.java).
Vulnerable code:
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String name = entry.getName();
// ❌ Incomplete check — only blocks entries starting with ".."
if (Paths.get(name).startsWith("..")) {
throw new UnsupportedOperationException("...");
}
if (name.startsWith("web/module/")) {
String filepath = name.substring(11);
StringBuilder absPath = new StringBuilder(realPath + "/WEB-INF");
absPath.append("/view/module/");
absPath.append(mod.getModuleIdAsPath()).append("/").append(filepath);
// ❌ No normalize() or startsWith() boundary check before writing
File outFile = new File(absPath.toString().replace("/", File.separator));
outStream = new FileOutputStream(outFile, false);
inStream = jarFile.getInputStream(entry);
OpenmrsUtil.copyFile(inStream, outStream);
}
}
Why the check fails: For an entry named web/module/foo/../../../../evil.jsp, Paths.get(name) starts with web, not .., so the check passes. After name.substring(11), the filepath foo/../../../../evil.jsp is concatenated directly into the output path without normalization, resulting in a write outside the intended directory.
Correctly protected code in the same codebase:
ModuleUtil.expandJar():
// ✅ Correct — uses normalize().startsWith()
if (!parent.toPath().normalize().startsWith(docBase)) {
throw new UnsupportedOperationException("...");
}
TestInstallUtil.addZippedTestModules():
// ✅ Correct — uses normalize().startsWith()
if (!zipEntryFile.toPath().normalize().startsWith(moduleRepository.toPath().normalize())) {
throw new IOException("Bad zip entry");
}
The fix pattern is already known and applied elsewhere in the codebase. WebModuleUtil.startModule() is an oversight.
Bypass of module.allow_web_admin
The module.allow_web_admin property only restricts module operations at the Legacy UI layer (ModuleListController). The REST API endpoint does not consult this property:
Legacy UI: POST /admin/modules/moduleList.form → allowAdmin() check → [BLOCKED]
REST API: POST /ws/rest/v1/module → No allowAdmin() check → [ALLOWED]
↓
ModuleFactory.loadModule()
↓
WebModuleUtil.startModule() ← Zip Slip here, no allowAdmin check
↓
FileOutputStream.write() ← Arbitrary file write
Remediation
Add normalize().startsWith() boundary validation before writing, consistent with the existing pattern in ModuleUtil.expandJar():
File outFile = new File(absPath.toString().replace("/", File.separator));
// ✅ Add this check
if (!outFile.toPath().normalize().startsWith(
Paths.get(realPath, "WEB-INF").normalize())) {
throw new UnsupportedOperationException(
"Zip entry '" + name + "' would be written outside the allowed directory.");
}
Additionally, enforce the module.allow_web_admin restriction consistently across all module upload entry points, including the REST API.
Betroffene Software
Klicken Sie auf eine Technologie, um alle zugehörigen Schwachstellen anzuzeigen.
| Plattform | Paket | Anfällige Versionen | Behoben in |
|---|---|---|---|
| Java / Kotlin (Maven) | org.openmrs.web:openmrs-web | <= 2.7.8, >= 2.8.0, <= 2.8.5 | keine Korrektur |
Verweise
- CVSS-Vektor
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N- Schwäche (CWE)
CWE-22- Plattform
- Java / Kotlin (Maven)
- Paket
org.openmrs.web:openmrs-web- Veröffentlicht
- 04.05.2026
- Aktualisiert
- 11.10.2026 12:22
Quellen und Lizenzen
OSV / GitHub Advisory Database - GHSA-78fc-9688-w8xw - CC BY 4.0
Schwachstellenhistorie: org.openmrs.web:openmrs-web
Alle veröffentlichten Schwachstellen dieses Pakets (Java / Kotlin (Maven)), neueste zuerst. Zeigt, ob es ein einmaliger Ausrutscher ist oder ein Paket, das man im Auge behalten muss.
- Einträge insgesamt
- 2
- Erste → letzte
- 05.2026 05.2026
- Ohne Fix
- 1
- In Angriffen ausgenutzt
- 0
Verteilung nach Schweregrad
- Kritisch 1
- Hoch 1
Veröffentlichungen pro Jahr
- 2026: 2
-
OpenMRS Module Upload Vulnerable to Path Traversal (Zip Slip) dieser Eintrag
Erkennen Sie Schwachstellen in Ihrer Anwendung
Mit der DockRay-Integration und aktivierter Softwareinventarisierung prüft DockRay gemeldete Komponentenversionen auf bekannte Schwachstellen und benachrichtigt Sie über bestätigte Treffer. Die Abdeckung hängt von der unterstützten Technologie und den verfügbaren Meldungen ab.