CVE-2026-47887
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Spring Framework is a widely used application framework for the Java platform that provides the core programming and configuration model for modern Java enterprise applications, including the Spring MVC servlet web stack. Spring MVC resolves the logical view name a controller returns into a concrete view, and its URL-based view resolvers give two view-name prefixes special meaning: a name beginning with redirect: sends the client an HTTP redirect to the remainder of the name, and a name beginning with forward: performs a server-side forward. The UrlFilenameViewController convenience controller derives the view name directly from the request URL path, so that a request for /products/view.html renders the view named products/view.
An open redirect vulnerability (CVE-2026-47887) has been identified in UrlFilenameViewController, which allows attackers to craft a link into an affected application that redirects the victim's browser to an arbitrary external site, or forwards the request to an internal resource of the attacker's choosing, because the controller passes the attacker-controlled path straight through as a view name without rejecting the redirect: and forward: prefixes. The vulnerability is only relevant when an application registers a UrlFilenameViewController, maps it with a pattern that ends in a path wildcard so that the trailing part of the URL becomes the view name, and does not configure a view-name prefix on the controller.
Per OWASP: Unvalidated redirects and forwards are possible when a web application accepts untrusted input that could cause the web application to redirect the request to a URL contained within untrusted input. By modifying untrusted URL input to a malicious site, an attacker may successfully launch a phishing scam and steal user credentials.
The advisory rates this vulnerability Medium severity with the CVSS v3.1 vector AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N, which corresponds to a base score of 4.2. The attack vector is Network because the crafted link is an ordinary HTTP request, attack complexity is High because the application must use the specific controller, mapping, and no-prefix configuration described above, user interaction is Required because a victim has to follow the attacker's link, and the Confidentiality and Integrity impacts are Low because the outcome is a phishing-style redirect rather than direct access to data inside the application.
This issue affects Spring Framework <=5.2.25, >=5.3.0 <=5.3.49, >=6.0.0 <=6.0.30, >=6.1.0 <=6.1.28, >=6.2.0 <=6.2.19, and >=7.0.0 <=7.0.8, including the End-of-Life 4.3.x, 5.3.x, 6.1.x, and 6.2.x lines supported by NES for Spring Framework.
Details
Module Info
- Product: Spring Framework
- Affected packages:
org.springframework:spring-webmvc - Affected versions: <=5.2.25, >=5.3.0 <=5.3.49, >=6.0.0 <=6.0.30, >=6.1.0 <=6.1.28, >=6.2.0 <=6.2.19, >=7.0.0 <=7.0.8
- GitHub repository: https://github.com/spring-projects/spring-framework
- Published packages: https://central.sonatype.com/artifact/org.springframework/spring-webmvc
- Package manager: Maven
- Fixed in:
- NES for Spring Framework nes-v4.3.40, nes-v5.3.54, nes-v6.1.30, and nes-v6.2.21
- Spring Framework 7.0.9 (OSS)
Vulnerability Info
This Medium-severity vulnerability is found in the spring-webmvc package in multiple versions of Spring Framework. UrlFilenameViewController is a ready-made controller that turns the request URL into a view name so that static view templates can be served without a dedicated handler method per page. It is typically registered through a SimpleUrlHandlerMapping with a pattern such as /pages/**, in which case the portion of the URL that matched the wildcard is stored in the request as the path within the handler mapping and becomes the input for view-name extraction:
protected String getViewNameForRequest(HttpServletRequest request) {
String uri = extractOperableUrl(request);
return getViewNameForUrlPath(uri);
}
protected String extractOperableUrl(HttpServletRequest request) {
String urlPath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
if (!StringUtils.hasText(urlPath)) {
urlPath = ServletRequestPathUtils.getCachedPathValue(request);
}
return urlPath;
}
protected String getViewNameForUrlPath(String uri) {
return this.viewNameCache.computeIfAbsent(uri,
key -> postProcessViewName(extractViewNameFromUrlPath(key)));
}
protected String extractViewNameFromUrlPath(String uri) {
int start = (uri.charAt(0) == '/' ? 1 : 0);
int lastIndex = uri.lastIndexOf('.');
int end = (lastIndex < 0 ? uri.length() : lastIndex);
return uri.substring(start, end);
}
protected String postProcessViewName(String viewName) {
return getPrefix() + viewName + getSuffix();
}
extractViewNameFromUrlPath only strips a leading slash and a trailing file extension, and postProcessViewName only concatenates the configured prefix and suffix, both of which default to the empty string. Nothing in this chain inspects the resulting view name, so whatever text the client places in the path becomes the view name verbatim. The controller returns that name in a ModelAndView, and DispatcherServlet hands it to the configured view resolvers.
UrlBasedViewResolver and the resolvers built on it, including the common InternalResourceViewResolver and FreeMarkerViewResolver, check the incoming view name for the redirect: and forward: prefixes before attempting a normal lookup. A name that starts with redirect: is turned into a RedirectView that sends the client to the URL following the prefix, and a name that starts with forward: becomes an InternalResourceView that forwards the request to the given path. These prefixes are a convenience for application code that returns view names, and the resolver cannot tell that the name in front of it originated from the request URL rather than from a controller. The redirect-host allowlist on the resolver is unset by default, so any absolute URL is accepted.
As a result, on an affected version with the controller mapped to a wildcard pattern and no prefix configured, a request for:
GET /pages/redirect:https://attacker.example/login.html HTTP/1.1
produces the view name redirect:https://attacker.example/login, and the application answers with an HTTP redirect to the attacker's site. Because the link begins with the legitimate application's own host, it looks trustworthy to the victim and is well suited to phishing for credentials or session tokens. The same path with a forward: prefix makes the application forward the request internally to a resource the attacker names, which can expose resources that were not meant to be reached through that mapping.
This vulnerability was introduced in 2005 with Spring Framework 1.2.6.
Steps to Reproduce
1. Add an affected version of spring-webmvc to a project, for example 6.2.19, together with spring-test for the mock servlet classes, and run the following against a plain UrlFilenameViewController, exposing the request path the way a wildcard handler mapping would:
UrlFilenameViewController controller = new UrlFilenameViewController();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/redirect:https://attacker.example/login.html");
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, request.getRequestURI());
ModelAndView mv = controller.handleRequest(request, new MockHttpServletResponse());
System.out.println(mv.getViewName());
2. Observe that the printed view name is redirect:https://attacker.example/login. When that ModelAndView is rendered through any UrlBasedViewResolver, the response is an HTTP redirect to https://attacker.example/login.
3. Repeat the same call on a patched version, for example 7.0.9, and observe that handleRequest throws a ResponseStatusException with status 400 Bad Request instead of returning the redirecting view name. The same holds for the path /forward:index.
Mitigation
Only recent versions of Spring Framework receive community support. The 4.3.x, 5.3.x, 6.1.x, and 6.2.x lines are End-of-Life and will not receive public updates to address this issue, so there is no publicly available fix for those lines other than through a commercial support partner.
Applications that cannot upgrade immediately can reduce their exposure by configuring a non-empty prefix on every UrlFilenameViewController, since a view name that begins with the prefix can no longer begin with redirect: or forward:, or by setting redirectHosts on their UrlBasedViewResolver so that redirects to hosts outside the allowlist are not honored.
Users of the affected components should apply one of the following mitigations:
- Upgrade to a currently supported version of Spring Framework. The open-source fix ships in Spring Framework 7.0.9 on the 7.0.x line.
- Leverage a commercial support partner like HeroDevs for post-EOL security support, which provides the fix for the 4.3.x, 5.3.x, 6.1.x, and 6.2.x lines in nes-v4.3.40, nes-v5.3.54, nes-v6.1.30, and nes-v6.2.21.
Credits
- No public finder credit is listed in the advisory sources checked for this entry.