FortiGuard Labs Threat Research

More Path Filter Bypass Vulnerabilities on Java Open Source Projects

By Thanh Nguyen Nguyen | September 09, 2022

A Uniform Resource Locator (URL), colloquially termed a web address, comprises five components: scheme, authority, path, query, and fragment. Each element is shown in this example: http://host-authority/path/?query-param=1#fragment

In the web application world, an URL path is always used to map a web request to a designated web service on the backend. As a security precaution, a web application typically has a path filter mechanism to prevent an unauthorized user from exploiting an unintended functionality via URL.

The Java web framework is one of the most widely deployed web services on the Internet. Based on our experience, many web servlets also rely on path filters to prevent unintended service access. (A servlet is a Java programming language class that extends the capabilities of servers that host applications that are accessed using a request-response programming model.) Because of this, we decided to perform a code audit on some popular Java open source projects. During our assessment, we found some interesting bypass vulnerabilities on two open source projects, Apache Shiro and dotCMS. These vulnerabilities have been designated as CVE-2021-41303 and CVE-2022-35740:

  • FG-VD-21-045: Apache Shiro Authentication Bypass when using Spring Boot
  • FG-VD-22-062: dotCMS XSSPreventionWebInterceptor Bypass using Matrix Parameter

In the next section, we will walk through the path filter bypass methods we discovered.

FG-VD-21-045: Apache Shiro Authentication Bypass when using Spring Boot (CVE-2021-41303)

Apache Shiro™ is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management.

There are two ways to use Apache Shiro: SSH and Web (when integrated into a web framework, like Spring and Spring Boot). In this article, we will talk about an authentication bypass vulnerability for Apache Shiro when using Spring Boot.

In the following demo, we create a Spring Boot application with Apache Shiro that protects the /admin/ path to prevent unauthorized user access.

Figure 1: Using Apache Shiro to protect the admin path against unauthorized access

Figure 2: Web Controller Path Mapping

When we try to access the “/admin/” path endpoint, we are redirected to the “/login” page. This is working as expected since we are unauthorized.

Figure 3: Request and Response when unauthorized access of /admin/test is attempted

However, the vulnerability exists due to the difference in how Apache Shiro and Spring Boot parse the URL Path. To verify this, we analyzed how a normal request to “/admin/aaa” is parsed. 

Figure 4: Accessing the /admin/aaa path

When accessing the path in Figure 4, the pathMatches method in Apache Shiro will be called. In Figures 5 and 6, we can see that it compares the pattern “/admin/*” with our input path “/admin/aaa” and returns true.

Figure 5: Code snippet of the pathMatches method

Figure 6: Evaluating “/admin/aaa”

Since it matches the admin route, but we are currently unauthorized, we are redirected to the login page. So far, this is all normal behavior.

Figure 7: Redirected to a login page

Now we will look at what happens when the malformed bypass request “/admin/%2e%2e” is sent.

Figure 8: Accessing /admin/%2e%2e

The pathMatches function is called, but this time it treats our input path as “/”, not “/admin/%2e%2e”

Figure 9: Debugging path value in the pathMatches method

Figure 10: Evaluating “/”

This is because when Apache Shiro tries to decode this URL path, it translates to “/admin/..” and hence goes back to the root directory. This bypasses the authentication check, as Apache Shiro treats it as equivalent to “/” (which is supposed to be publicly accessed). Apache Shiro then forwards the request to Spring Boot for processing.

However, this same input is treated differently in Spring Boot Path Mapping. In this case, it sees this as an endpoint under “/admin/” and serves up the protected content to the attacker, as seen in Figure 11.

Figure 11: Authentication Bypass on a protected endpoint

Due to the difference in parsing between Apache Shiro and Spring Boot, we managed to successfully bypass the authentication mechanism of Apache Shiro.


  • 31 March 2021: Fortinet reported the vulnerability to Apache Shiro
  • 13 April 2021: Apache Shiro team confirmed the vulnerability
  • 24 August 2021: Apache Shiro released a patch for the issue
  • 16 September 2021: CVE-2021-41303 is assigned to this vulnerability
  • 11 August 2022: Fortinet released the IPS signature, Apache.Shiro.Authentication.Bypass, to protect Fortinet customers.
  • 8 September 2022: Fortinet published an article detailing this vulnerability.

FG-VD-22-063: dotCMS XSSPreventionWebInterceptor Bypass using Matrix Parameter (CVE-2022-35740)

dotCMS is an Open Source Hybrid CMS (content management system) built on Java. While assessing dotCMS, we found several CORS Attack, Cross-Site Request Forgery, and Cross-Site Scripting issues that could lead to critical threats if users with admin privilege access them.

However, we also realized that these issues might not be exploitable since dotCMS has XSS Prevention enabled globally by default on all their administrative endpoints.

A quick look at the documentation shows that dotCMS blocks direct access to all files under the administrative directories (e.g.,/html, /dotAdmin, etc.) unless a request is sent with a valid Referer or Origin header.

To verify this, we tried to access one of the endpoints with an XSS payload. 





The application redirects the user back to /dotAdmin/ due to the absence of a Referer or Origin header.

Figure 12: Request and Response when accessing a protected path without a Referer Header

To better understand how the path filter mechanism works in dotCMS, we decided to dive into the code to see if there is a way to bypass it.

Looking at the dotCMS version 22.05 source code, in com​/dotcms​/filters​/interceptor​/dotcms​/XSSPreventionWebInterceptor​.java from line 28, we find that it defines which paths are protected by default. 

Figure 13: Protected Path of the XSS Prevention mechanism

Any incoming request that matches the protected path will be intercepted and passed to securityUtils.validateReferer() in com/dotcms/util/

Figure 14: Code Snippet of the intercept method

Figure 15: Code Snippet of the validateReferer method

Basically, this method checks whether:

  • The Origin/Referer has the same host name as the requested URL (usually, this is the case).
  • The Origin/Referer header has a value equal to a site or alias defined in the site manager (not normal, but maybe).
  • The Origin/Referer header has a value equal to the “Portal URL” defined on the Configuration Screen.
  • The request is for a *.css file (CSS @import statements do not set a referer).

If true, the request will proceed. Otherwise, it sets the status to 401 Unauthorized to the response or redirects to an exception page.

Instead of attempting to bypass the Origin/Referer header, we thought of an easier approach. Why not perform a bypass on PATH instead? In this case, if the path doesn’t match the Protected Path, we no longer need to deal with the validation.

With that idea in mind, we found the bypass using matrix parameters, which are an alternative to query parameters but more flexible and can be accepted anywhere in the path.

For example, given a query parameter of:


We can transform it into a matrix parameter with the same meaning:


Knowing this, we can transform our intended payload into a matrix parameter, effectively bypassing the whitelist.





Figure 16: Request and Response when accessing a protected path with Matrix Parameter without a Referer Header

As seen in Figure 16, the request successfully bypassed the XSS protection, and the unsanitized XSS payload is reflected in the output.


  • 10 June 2022: Fortinet reported the vulnerability to dotCMS
  • 21 June 2022: dotCMS team confirmed the vulnerability and asked for 60 days delay to mitigate the issue and inform their customers
  • 28 June 2022: dotCMS released a patch for the issue
  • 17 July 2022: CVE-2022-35740 is assigned to this vulnerability
  • 1 August 2022: Fortinet released an IPS signature to protect Fortinet customers
  • 17 August 2022: dotCMS team asked to hold the publication of the vulnerability for a few additional weeks as vendors still have on-premises customers who need to remediate the issue.
  • 8 September 2022: Fortinet publishes an article detailing this vulnerability


In conclusion, path filter mechanisms can go wrong easily, and it takes significant effort to implement a comprehensive filter mechanism. In addition to the two examples we presented here, we have seen numerous examples provided by other researchers on how a path filter can be trivially escaped.

However, another important lesson learned is that when developers create a product that is being integrated into or relies on another framework, they should make sure they fully understand the nature of the framework. This will help ensure they do not inadvertently introduce a vulnerability like the one we described on Apache Shiro.

Fortinet Protections

FortiGuard Labs released the following IPS signatures, which cover all the vulnerabilities mentioned:



Users are also strongly urged to apply the latest patched from the vendors:

Apache Shiro:


NOTE: If you are interested in this kind of assessment for your software or application, FortiGuard Labs provides a tailor-made vulnerability assessment and penetration testing service that can help you improve the security of your products. Visit us here for more information. 

Learn more about Fortinet’s FortiGuard Labs threat research and global intelligence organization and Fortinet’s FortiGuard AI-powered Security Services portfolio. Sign up to receive our threat research blogs.