Skip to main content

OpenMRS Core CVE-2026-40076

CRITICAL
Path Traversal (CWE-22)
2026-05-04 https://github.com/openmrs/openmrs-core GHSA-78fc-9688-w8xw
9.4
CVSS 4.0 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
9.4 CRITICAL
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
X

Lifecycle Timeline

7
Re-analysis Queued
May 06, 2026 - 20:22 vuln.today
cvss_changed
Severity Changed
May 06, 2026 - 20:22 NVD
HIGH CRITICAL
CVSS changed
May 06, 2026 - 20:22 NVD
8.7 (HIGH) 9.4 (CRITICAL)
Source Code Evidence Fetched
May 04, 2026 - 18:03 vuln.today
Analysis Generated
May 04, 2026 - 18:03 vuln.today
Analysis Generated
May 04, 2026 - 17:45 vuln.today
CVE Published
May 04, 2026 - 17:39 nvd
HIGH 8.7

DescriptionGitHub Advisory

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

  1. Construct a malicious .omod file (which is a ZIP/JAR archive) containing a ZIP entry with a path traversal payload in its entry name, such as web/module/../../../../<target_filename>. Upload this file to POST /openmrs/ws/rest/v1/module with valid admin credentials via Basic Auth.

<img width="1986" height="1102" alt="image" src="https://github.com/user-attachments/assets/647f15de-7e8c-40b9-aba9-d4db5d2e0b52" />

<img width="2048" height="1078" alt="image" src="https://github.com/user-attachments/assets/301412a0-e3b0-4afb-91c2-e9739de3080d" />

  1. The server parses and loads the module. During WebModuleUtil.startModule(), entries under web/module/ are automatically extracted. The existing check Paths.get(name).startsWith("..") only blocks entries beginning with .., so an entry starting with web/module/ passes the check. The ../ sequences in the remaining path cause the file to be written outside the intended WEB-INF/view/module/ directory - for example, into the web application root at /usr/local/tomcat/webapps/openmrs/.

<img width="1439" height="141" alt="image" src="https://github.com/user-attachments/assets/4bda3b1e-a80e-42ed-af2b-a1da53e8db03" />

  1. 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.

<img width="1482" height="300" alt="image" src="https://github.com/user-attachments/assets/61936002-78cd-4203-80f0-f0a8702b216c" />

Root Cause Analysis

The vulnerability exists in WebModuleUtil.startModule() (web/src/main/java/org/openmrs/module/web/WebModuleUtil.java).

Vulnerable code:

java
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():

java
// ✅ Correct - uses normalize().startsWith()
if (!parent.toPath().normalize().startsWith(docBase)) {
    throw new UnsupportedOperationException("...");
}

TestInstallUtil.addZippedTestModules():

java
// ✅ 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():

java
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.

AnalysisAI

Path traversal (Zip Slip) vulnerability in OpenMRS Core ≤ 2.7.8 and 2.8.0-2.8.5 allows authenticated administrators to achieve remote code execution by uploading a malicious .omod module archive to the REST API endpoint POST /openmrs/ws/rest/v1/module. Attackers can write arbitrary JSP files to the Tomcat webroot via crafted ZIP entries containing directory traversal sequences (e.g., web/module/../../../../malicious.jsp), which bypass incomplete path validation in WebModuleUtil.startModule(). The vulnerability also bypasses the module.allow_web_admin security control, as the REST API does not enforce this restriction despite Legacy UI being protected. No vendor-released patch identified at time of analysis for either affected version range.

Technical ContextAI

OpenMRS (Open Medical Record System) is a Java-based electronic health record platform commonly deployed on Apache Tomcat. The vulnerability resides in the module upload functionality that processes .omod files (custom ZIP/JAR archives containing OpenMRS plugins). CWE-22 (Path Traversal) manifests here because WebModuleUtil.startModule() performs an incomplete boundary check using Paths.get(name).startsWith(".."), which only blocks entries beginning with literal ".." but fails to detect traversal sequences embedded after a valid prefix like "web/module/". After substring extraction, the filepath is concatenated directly into the output path without normalization, allowing an attacker to write files outside the intended WEB-INF/view/module/ directory. Ironically, other extraction methods in the same codebase (ModuleUtil.expandJar(), TestInstallUtil.addZippedTestModules()) correctly implement normalize().startsWith() boundary checks, making this a localized oversight rather than a systematic design flaw. The Maven package org.openmrs.web:openmrs-web (confirmed by CPE data) is affected in two version ranges: legacy versions ≤ 2.7.8 and newer versions 2.8.0-2.8.5.

RemediationAI

No vendor-released patch identified at time of analysis for either affected version range (≤ 2.7.8 or 2.8.0-2.8.5). OpenMRS community advisory at https://github.com/openmrs/openmrs-core/security/advisories/GHSA-78fc-9688-w8xw recommends applying normalize().startsWith() boundary validation in WebModuleUtil.startModule() before writing extracted files, consistent with the pattern already used in ModuleUtil.expandJar(). Until a patched release is available, implement compensating controls: (1) Disable the REST API module upload endpoint POST /openmrs/ws/rest/v1/module at the reverse proxy or servlet filter level - trade-off is administrators must use CLI or filesystem-based module deployment; (2) Enforce strict module.allow_web_admin=false in runtime properties AND patch the REST API to honor this property by adding the allowAdmin() check before calling ModuleFactory.loadModule() - note this only prevents upload via web, not exploitation if malicious modules already exist; (3) Restrict administrative access to the REST API using network segmentation, IP allowlisting, or mutual TLS to minimize attack surface - does not prevent insider threats or credential compromise; (4) Enable Tomcat SecurityManager with strict file write permissions to prevent writes outside WEB-INF/view/module/ - may break legitimate module functionality and requires extensive testing. Monitor for suspicious .omod uploads and unexpected JSP files in webroot using file integrity monitoring. Patching guidance in advisory suggests adding outFile.toPath().normalize().startsWith(Paths.get(realPath, "WEB-INF").normalize()) check before FileOutputStream instantiation.

More in Java

View all
CVE-2012-4681 CRITICAL POC
9.8 Aug 28

Oracle Java SE 7 Update 6 and earlier contains multiple sandbox bypass vulnerabilities via the ClassFinder and forName m

CVE-2015-7450 CRITICAL POC
9.8 Jan 02

Remote code execution in IBM Sterling B2B Integrator, Sterling Integrator, and Tivoli Common Reporting allows unauthenti

CVE-2013-2465 CRITICAL POC
9.8 Jun 18

Java Runtime Environment sandbox bypass via incorrect image channel verification in 2D component allows remote unauthent

CVE-2011-3544 CRITICAL POC
9.8 Oct 19

Oracle Java SE JDK/JRE 7 and 6 Update 27 and earlier allows remote code execution with complete system compromise throug

CVE-2010-1871 HIGH POC
8.8 Aug 05

JBoss Seam 2 in Red Hat JBoss EAP 4.3.0 fails to sanitize JBoss Expression Language inputs, allowing remote attackers to

CVE-2012-1723 CRITICAL POC
9.8 Jun 16

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 update 4 and earlier, 6 up

CVE-2013-0422 CRITICAL POC
9.8 Jan 10

Multiple vulnerabilities in Oracle Java 7 before Update 11 allow remote attackers to execute arbitrary code by (1) using

CVE-2012-0507 CRITICAL POC
9.8 Jun 07

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 Update 2 and earlier, 6 Up

CVE-2015-4852 CRITICAL POC
9.8 Nov 18

The WLS Security component in Oracle WebLogic Server 10.3.6.0, 12.1.2.0, 12.1.3.0, and 12.2.1.0 allows remote attackers

CVE-2012-5076 CRITICAL POC
9.8 Oct 16

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 Update 7 and earlier allow

CVE-2017-3066 CRITICAL POC
9.8 Apr 27

Remote unauthenticated attackers can execute arbitrary code on Adobe ColdFusion servers through Java deserialization fla

CVE-2012-0391 CRITICAL POC
9.8 Jan 08

The ExceptionDelegator component in Apache Struts before 2.2.3.1 interprets parameter values as OGNL expressions during

Share

CVE-2026-40076 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy