Why %2e Path Normalization in Spring Boot ≤2.3.0 Lets Attackers Bypass Authentication

This article explains how Spring Boot versions up to 2.3.0.RELEASE normalize URLs containing the %2e sequence, causing servlet path handling that can be exploited to bypass authentication, and shows why the behavior changes in later releases.

Programmer DD
Programmer DD
Programmer DD
Why %2e Path Normalization in Spring Boot ≤2.3.0 Lets Attackers Bypass Authentication

Spring Boot versions ≤ 2.3.0.RELEASE have alwaysUseFullPath set to false by default, which makes the framework use ServletPath for route matching. During this process the URL is normalized, decoding %2e (".") and handling directory‑traversal segments, which can lead to authentication bypass.

Example

Set the parent version to 2.3.0.RELEASE in pom.xml:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

Create a simple controller with two endpoints:

@RestController
public class httpbinController {
    @RequestMapping(value = "no-auth", method = RequestMethod.GET)
    public String noAuth() { return "no-auth"; }

    @RequestMapping(value = "auth", method = RequestMethod.GET)
    public String auth() { return "auth"; }
}

Configure an interceptor that blocks every request except the /no-auth path:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(handlerInterceptor()).addPathPatterns("/**");
    }
    @Bean
    public HandlerInterceptor handlerInterceptor() { return new PermissionInterceptor(); }
}

@Component
public class PermissionInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String uri = request.getRequestURI().replaceAll("//", "/");
        if (uri.contains("..") || uri.contains("./")) return false;
        if (uri.startsWith("/no-auth")) return true;
        return false;
    }
}

Sending a request with an encoded directory‑traversal segment bypasses the interceptor:

$ curl -v "http://127.0.0.1:8080/no-auth/%2e%2e/auth"
... (HTTP 200, body "auth")
RequestURI: /no-auth/%2e%2e/auth

The request URI still contains %2e%2e, but because alwaysUseFullPath is false, Spring resolves the servlet path, decodes %2e, and treats the path as /no-auth/../auth, which matches the /auth handler.

Behavior in 2.3.1+

In Spring Boot 2.3.1.RELEASE the default for alwaysUseFullPath is changed to true. The framework now uses the full request path ( getPathWithinApplication) without the extra normalization, so the same %2e%2e request results in a 404.

Underlying methods:

org.springframework.web.util.UrlPathHelper#getLookupPathForRequest(HttpServletRequest)

– uses getPathWithinServletMapping when alwaysUseFullPath is false, which normalizes the path. getPathWithinApplication – only decodes the URI and does not re‑process directory‑traversal segments.

The change was introduced for efficiency when the servlet mapping is "/"; the commit can be found at spring‑boot‑autoconfigure#configurePathMatch .

Because the same normalization logic also appears in Shiro’s UrlPathHelper integration, the issue aligns with CVE‑2020‑17523 when alwaysUseFullPath is true in newer Spring Boot releases.

In summary, for Spring Boot ≤ 2.3.0.RELEASE the default alwaysUseFullPath=false causes servlet‑path‑based normalization that decodes %2e and can be abused to bypass authentication, while later versions set the flag to true, changing the matching behavior and exposing a related risk in Shiro integrations.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Spring BootSecurityPath NormalizationAuthentication BypassalwaysUseFullPath
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.