We recently discovered a path traversal vulnerability in Grandnode v4.40. This issue allows unauthenticated users to retrieve any files accessible to the web application. If the application is run under administrative permissions, the damage can be significant. This vulnerability was reproduced on Windows and Linux.

We tested Grandnode v4.40, but previous versions may also be affected.


Date Action
05/16/2019 Vulnerability discovered by Security401
05/17/2019 Reached out to vendor to request the preferred method of reporting the issue.
05/20/2019 Reached out to the main code contributer to report the issue.
05/28/2019 Reached via the product forum to request preferred method of reporting the issue.
05/30/2019 Issue acknowledged and fixed by the vendor.


The fix was added in this commit, please be sure to upgrade your installation if your version of Grandnode is older than 05/30/2019.


Grandnode is an open source eCommerce solution powered by .NET Core 2.2, supporting Windows, Linux and Mac operating systems.

Technical Details

The vulnerability exists in LetsEncryptController.cs in the Index action method. This method is used in the Let’s Encrypt HTTP challenge to validate domain ownership of the domain(s) in a certificate request. As part of the certification process, the ACME client will generate a token file on the web server which will be publicly accessible from a URL in the format below:


Grandnode exposes this URL by mapping this route to the LetsEncryptController:

routeBuilder.MapRoute("well-known", ".well-known/acme-challenge/{fileName}", 
    new { controller = "LetsEncrypt", action = "Index" });

routeBuilder.MapRoute("well-known", ".well-known/acme-challenge/{fileName}", 
    new { controller = "LetsEncrypt", action = "Index" });

In the final steps, Let's Encrypt's servers will attempt to retrieve this token file from the URL to perform validation and if successful, issue a certificate. In order for this process to work, Let's Encrypt's servers must be able to access the token validation URL without authenticating. This is accomplished via the [AllowAnonymous] attribute on the LetsEncryptController class.

public partial class LetsEncryptController : Controller
  public virtual IActionResult Index(string fileName)
    if (fileName == null)
      return Content("");

    var file = Path.Combine(CommonHelper.MapPath("~/wwwroot/content/acme/"), 

    if (System.IO.File.Exists(file))
      return new PhysicalFileResult(file, "text/plain");
    return Content("");

The expectation is that only token files will be retrieved from this endpoint. Unfortunately, the application does not perform any validation to ensure that this is the case. By specifying a fully-qualified path, an unauthorized attacker can download any file in which the application has read permissions to. It is worth noting that we were not able to exploit this issue via the Let's Encrypt endpoint.


Each attempt to add a fully-qualified file in the REST style URL resulted in a Page not found error. However, we can still access the controller method using the convention routing format:


Reproduction Steps

This issue can be reproduced with the curl commands as shown below or simply browsing to the site and specifying an absolute file path:

curl -i -s -k -H $'Connection: close' \
Path Traversal in Linux
curl -i -s -k -H $'Connection: close' \ 
Path Traversal in Windows

A python POC for this issue can be found here.