Alta

OpenMRS ModuleResourcesServlet has Path Traversal that Leads to Arbitrary File Read

  • Publicada: 04.05.2026
  • Actualizado: 11.10.2026 12:22

Affected Versions

version ≤ 2.7.8 (latest version at time of disclosure)

https://github.com/openmrs/openmrs-core

Impact

The /openmrs/moduleResources/{moduleid} endpoint in OpenMRS Core is vulnerable to a path traversal attack. The ModuleResourcesServlet does not properly validate user-supplied path input, allowing an attacker to traverse directories and read arbitrary files from the server filesystem (e.g., /etc/passwd, application configuration files containing database credentials).

This endpoint serves static module resources (CSS, JS, images) and is not protected by authentication filters, as these resources are required for rendering the login page. Therefore, this vulnerability can be exploited by an unauthenticated attacker.

Note: Successful exploitation requires the target deployment to run on Apache Tomcat < 8.5.31, where the ..; path parameter bypass is not mitigated by the container. Deployments on Tomcat ≥ 8.5.31 / ≥ 9.0.10 are protected at the container level, though the underlying code defect remains.

Steps to Reproduce

  1. Identify a valid installed module ID on the target OpenMRS instance (e.g., legacyui).
  2. Send the following HTTP request:
<img width="1038" height="798" alt="image" src="https://github.com/user-attachments/assets/7d10ee0e-4d81-4c01-bc84-a1bf5715f170" />
  1. The server responds with HTTP 200 and the contents of /etc/passwd:
<img width="1028" height="843" alt="image" src="https://github.com/user-attachments/assets/b6806a7e-ff52-4f51-8f7f-7ea4e9754d10" />

Root Cause Analysis

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

The getFile() method constructs a filesystem path from user-controlled input without performing path boundary validation:

java
protected File getFile(HttpServletRequest request) {
    // Step 1: User-controlled path input
    String path = request.getPathInfo();

    // Step 2: Extract module from path prefix
    Module module = ModuleUtil.getModuleForPath(path);
    if (module == null) { return null; }

    // Step 3: Strip module ID prefix — no traversal check
    String relativePath = ModuleUtil.getPathForResource(module, path);

    // Step 4: Concatenate into absolute path
    String realPath = getServletContext().getRealPath("")
        + MODULE_PATH
        + module.getModuleIdAsPath()
        + "/resources"
        + relativePath;  // contains "/../../../etc/passwd"

    realPath = realPath.replace("/", File.separator);

    // Step 5: No normalize().startsWith() boundary check
    File f = new File(realPath);
    if (!f.exists()) { return null; }

    return f;  // Arbitrary file returned to client
}

The helper method ModuleUtil.getPathForResource() only strips the module ID prefix and performs no sanitization:

java
public static String getPathForResource(Module module, String path) {
    if (path.startsWith("/")) {
        path = path.substring(1);
    }
    return path.substring(module.getModuleIdAsPath().length());
    // Returns unsanitized remainder, e.g., "/../../../../../../etc/passwd"
}

The resulting path resolves as:

{webapp}/WEB-INF/view/module/legacyui/resources/../../../../../../etc/passwd
  → /etc/passwd

Notably, the same codebase already implements correct path traversal protection in StartupFilter.java:

java
// StartupFilter.java — correct protection
fullFilePath = fullFilePath.resolve(httpRequest.getPathInfo());
if (!(fullFilePath.normalize().startsWith(filePath))) {
    log.warn("Detected attempted directory traversal...");
    return;  // Request rejected
}

This check is absent from ModuleResourcesServlet.

Remediation

Add a path boundary check after constructing realPath and before returning the File object. The fix should use normalize() + startsWith() to ensure the resolved path stays within the allowed module resources directory:

java
File f = new File(realPath);
Path allowedBase = Paths.get(getServletContext().getRealPath(""), "WEB-INF", "view", "module");
if (!f.toPath().normalize().startsWith(allowedBase.normalize())) {
    log.warn("Blocked path traversal attempt: {}", request.getPathInfo());
    return null;
}

This is consistent with the existing pattern used in StartupFilter.java and TestInstallUtil.java within the same project.

Software afectado

Haz clic en una tecnología para ver todas sus vulnerabilidades.

PlataformaPaqueteVersiones vulnerablesCorregida en
Java / Kotlin (Maven) org.openmrs.web:openmrs-web <= 2.7.8, >= 2.8.0, < 2.8.6 2.8.6

Referencias

Puntuación CVSS 7.5/10
Vector CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Debilidad (CWE)
CWE-22
Plataforma
Java / Kotlin (Maven)
Paquete
org.openmrs.web:openmrs-web
Publicada
04.05.2026
Actualizado
11.10.2026 12:22

Fuentes y licencias

OSV / GitHub Advisory Database - GHSA-jjgj-cx3q-pw4w - CC BY 4.0

Historial de vulnerabilidades: org.openmrs.web:openmrs-web

Todas las vulnerabilidades publicadas de este paquete (Java / Kotlin (Maven)), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.

Entradas en total
2
Primera → última
05.2026 05.2026
Sin corrección
1
Explotada en ataques
0

Distribución por gravedad

  • Crítica 1
  • Alta 1

Divulgaciones por año

  1. 2026: 2
  1. Crítica · 8.7 CVE-2026-40076 <= 2.7.8, >= 2.8.0, <= 2.8.5 sin corrección
  2. OpenMRS ModuleResourcesServlet has Path Traversal that Leads to Arbitrary File Read esta entrada
    Alta · 7.5 CVE-2026-40075 <= 2.7.8, >= 2.8.0, < 2.8.6 2.8.6

Identifica las vulnerabilidades de tu aplicación

Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.

Conectar tu aplicación
Newsletter DockRay

La seguridad de tus aplicaciones en tu correo

Vulnerabilidades importantes, recomendaciones concretas y consejos prácticos para tus aplicaciones. Elige tus tecnologías y sigue lo que importa para tu proyecto.

  • Un resumen diario de nuevas vulnerabilidades, también las críticas.
  • Avisos sobre actualizaciones importantes.
  • Consejos prácticos sobre seguridad y monitorización de aplicaciones.

Déjalo vacío para recibir avisos de todas las tecnologías.

Suscripción gratuita. Date de baja con un clic en cualquier correo.