LogicalDOC 8.2 Path Traversal Vulnerability

LogicalDOC Path Traversal

LogicalDOC is a global software company offering a popular Java-based document management solution as a community or enterprise edition of the same name. In this blog post we will examine a path traversal vulnerability (CVE-2019-9723) which allows malicious guest users to steal arbitrary documents and files from the server.


In order to exploit this vulnerability an attacker needs to be an authenticated read-only user of the role guest. The attacker can read arbitrary files and create arbitrary directories on the server with the permissions of the user running the web server. It is recommended to update LogicalDOC to the newest release 8.2.1.

Technical Analysis

The vulnerability was found with the latest RIPS 3.0 engine that supports Java code analysis. The complete security analysis of roughly 200.000 code lines was performed in 30 minutes.

Path Traversal in DownloadServlet

The DownloadServlet of LogicalDOC acts as an interface for users to download managed documents. This servlet invokes a function called downloadPluginResource(). This function allows the download of plugin files which are installed in the plugin directory. Due to a lack of input sanitization an attacker can use path traversal to download arbitrary files with the rights of the web server. The following listing shows an excerpt of the DownloadServlet which extends Java’s HttpServlet. The function doGet() handles all incoming GET requests to the specified servlet. We can see that the function downloadPluginResource() is directly called with the GET parameters pluginId, resourcePath and fileName (line 7-9).


 1 2 3 4 5 6 7 8 9101112
public class DownloadServlet extends HttpServlet 

  public void doGet(HttpServletRequest request, HttpServletResponse response) 
    ServletUtil.downloadPluginResource(request, response, session.getSid(),
	request.getParameter("pluginId"), request.getParameter("resourcePath"),

In the function downloadPluginResource() the GET parameter pluginId becomes variable pluginName. As we can see in the following listing, the unsanitized user input flows into the function getPluginResource() of the class PluginRegistry (line 8). The application creates a new FileInputStream of the file in line 13 and writes this stream to the OutputStream of the response in line 19.


 1 2 3 4 5 6 7 8 91011121314151617181920212223
public class ServletUtil  

  public static void downloadPluginResource(HttpServletRequest request, 
	HttpServletResponse response, String sid, String pluginName, String resourcePath, String fileName)
    File file = PluginRegistry.getPluginResource(pluginName, resourcePath);
    String mimetype = MimeType.getByFilename(filename);
    InputStream is = null;
    ServletOutputStream os = null;

    is = new FileInputStream(file);
    os = response.getOutputStream();
    int letter = false;
    byte[] buffer = new byte[131072];
    while((letter = is.read(buffer)) != -1) 
      os.write(buffer, 0, letter);

In case we can control the variable file, we are able to download arbitrary files. To confirm that this issue is an exploitable vulnerability we have to take a closer look at the function getPluginResource() called in line 8.


 1 2 3 4 5 6 7 8 910
public static File getPluginResource(String pluginName, String path) 
   File root = getPluginHome(pluginName);
   File resource = new File(root.getPath() + "/" + path);
   if (!resource.exists() && !path.contains("."))
  return resource;

This function proves that the unsanitized variable path directly flows into the sensitive sink java.io.File in line 4 which can be exploited by an attacker using a path traversal attack (../). But not only the variable path is controlled by the attacker also the variable pluginName which flows into the function getPluginHome().

The following code snipped shows an excerpt of the function getPluginHome(). There is again no input validation or input sanitization applied on the attacker controlled variable pluginName. This causes another path traversal issue and allows the creation of directories.


 1 2 3 4 5 6 7 8 910
public static File getPluginHome(String pluginName) 
   File root = getPluginsDir();
   File userDir = new File(root, pluginName);
   if (!userDir.exists()) 
   return userDir;


By analyzing the web.xml file of the web application we can see that the URL pattern /download invokes the affected DownloadServlet.


 1 2 3 4 5 6 7 8 91011

An attacker can exploit the described vulnerability by using path traversal character sequences (../) in the pluginId parameter. This way the current working directory can be changed and the Java file constructor is pointed to a different file on the file system that will be opened and displayed. As a result, the attacker can leak arbitrary files.

Time Line

2019/01/02Vulnerability reported to LogicalDOC
2019/01/02Vendor acknowledged vulnerability and addressed issue in release 8.2.
2019/01/25Vendor published release 8.2 without verifying the fix.
2019/02/19Informed vendor about insufficient fix. Release 8.2 is still vulnerable.
2019/03/08Vendor released fixed version 8.2.1.


In this blog post we analyzed a serious vulnerability in a popular Java-based document management solution. It allows a read-only user with the least privileges to read sensitive documents on the server that are not approved for his or her user account. Further, the attacker can read any other file on the file system and escalate the attack. We highly recommend to update your LogicalDOC instances to the latest version 8.2.1.

Tags: java, security, logicaldoc, path traversal, file manipulation,

Author: Johannes Moritz

Security Researcher

Johannes is a security researcher at RIPS Technologies and is passionate about finding all types of security bugs, not only in web applications but also in Android apps and other systems. He studied IT security at the Ruhr-University Bochum and collected experience as a penetration tester.

Is your application secure?  Scan Your Code

Related Posts


comments powered by Disqus