VYPR
High severity7.5GHSA Advisory· Published Dec 19, 2024· Updated Apr 15, 2026

CVE-2024-38819

CVE-2024-38819

Description

Applications serving static resources through the functional web frameworks WebMvc.fn or WebFlux.fn are vulnerable to path traversal attacks. An attacker can craft malicious HTTP requests and obtain any file on the file system that is also accessible to the process in which the Spring application is running.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.springframework:spring-webfluxMaven
>= 6.1.0, < 6.1.146.1.14
org.springframework:spring-webmvcMaven
>= 6.1.0, < 6.1.146.1.14
org.springframework:spring-webfluxMaven
<= 5.3.39
org.springframework:spring-webmvcMaven
<= 5.3.39
org.springframework:spring-webfluxMaven
>= 6.0.0, <= 6.0.23
org.springframework:spring-webmvcMaven
>= 6.0.0, <= 6.0.23

Affected products

1

Patches

2
fb7890d73975

Update processPath for double encoding

4 files changed · +64 32
  • spring-webflux/src/main/java/org/springframework/web/reactive/function/server/PathResourceLookupFunction.java+16 8 modified
    @@ -148,20 +148,28 @@ else if (path.charAt(i) > ' ' && path.charAt(i) != 127) {
     	}
     
     	private static String normalizePath(String path) {
    -		if (path.contains("%")) {
    -			try {
    -				path = URLDecoder.decode(path, StandardCharsets.UTF_8);
    +		String result = path;
    +		if (result.contains("%")) {
    +			result = decode(result);
    +			if (result.contains("%")) {
    +				result = decode(result);
     			}
    -			catch (Exception ex) {
    -				return "";
    -			}
    -			if (path.contains("../")) {
    -				path = StringUtils.cleanPath(path);
    +			if (result.contains("../")) {
    +				return StringUtils.cleanPath(result);
     			}
     		}
     		return path;
     	}
     
    +	private static String decode(String path) {
    +		try {
    +			return URLDecoder.decode(path, StandardCharsets.UTF_8);
    +		}
    +		catch (Exception ex) {
    +			return "";
    +		}
    +	}
    +
     	private boolean isInvalidPath(String path) {
     		if (path.contains("WEB-INF") || path.contains("META-INF")) {
     			return true;
    
  • spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java+16 8 modified
    @@ -567,20 +567,28 @@ else if (path.charAt(i) > ' ' && path.charAt(i) != 127) {
     	}
     
     	private static String normalizePath(String path) {
    -		if (path.contains("%")) {
    -			try {
    -				path = URLDecoder.decode(path, StandardCharsets.UTF_8);
    +		String result = path;
    +		if (result.contains("%")) {
    +			result = decode(result);
    +			if (result.contains("%")) {
    +				result = decode(result);
     			}
    -			catch (Exception ex) {
    -				return "";
    -			}
    -			if (path.contains("../")) {
    -				path = StringUtils.cleanPath(path);
    +			if (result.contains("../")) {
    +				return StringUtils.cleanPath(result);
     			}
     		}
     		return path;
     	}
     
    +	private static String decode(String path) {
    +		try {
    +			return URLDecoder.decode(path, StandardCharsets.UTF_8);
    +		}
    +		catch (Exception ex) {
    +			return "";
    +		}
    +	}
    +
     	/**
     	 * Check whether the given path contains invalid escape sequences.
     	 * @param path the path to validate
    
  • spring-webmvc/src/main/java/org/springframework/web/servlet/function/PathResourceLookupFunction.java+16 8 modified
    @@ -149,20 +149,28 @@ else if (path.charAt(i) > ' ' && path.charAt(i) != 127) {
     	}
     
     	private static String normalizePath(String path) {
    -		if (path.contains("%")) {
    -			try {
    -				path = URLDecoder.decode(path, StandardCharsets.UTF_8);
    +		String result = path;
    +		if (result.contains("%")) {
    +			result = decode(result);
    +			if (result.contains("%")) {
    +				result = decode(result);
     			}
    -			catch (Exception ex) {
    -				return "";
    -			}
    -			if (path.contains("../")) {
    -				path = StringUtils.cleanPath(path);
    +			if (result.contains("../")) {
    +				return StringUtils.cleanPath(result);
     			}
     		}
     		return path;
     	}
     
    +	private static String decode(String path) {
    +		try {
    +			return URLDecoder.decode(path, StandardCharsets.UTF_8);
    +		}
    +		catch (Exception ex) {
    +			return "";
    +		}
    +	}
    +
     	private boolean isInvalidPath(String path) {
     		if (path.contains("WEB-INF") || path.contains("META-INF")) {
     			return true;
    
  • spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java+16 8 modified
    @@ -726,20 +726,28 @@ else if (path.charAt(i) > ' ' && path.charAt(i) != 127) {
     	}
     
     	private static String normalizePath(String path) {
    -		if (path.contains("%")) {
    -			try {
    -				path = URLDecoder.decode(path, StandardCharsets.UTF_8);
    +		String result = path;
    +		if (result.contains("%")) {
    +			result = decode(result);
    +			if (result.contains("%")) {
    +				result = decode(result);
     			}
    -			catch (Exception ex) {
    -				return "";
    -			}
    -			if (path.contains("../")) {
    -				path = StringUtils.cleanPath(path);
    +			if (result.contains("../")) {
    +				return StringUtils.cleanPath(result);
     			}
     		}
     		return path;
     	}
     
    +	private static String decode(String path) {
    +		try {
    +			return URLDecoder.decode(path, StandardCharsets.UTF_8);
    +		}
    +		catch (Exception ex) {
    +			return "";
    +		}
    +	}
    +
     	/**
     	 * Check whether the given path contains invalid escape sequences.
     	 * @param path the path to validate
    
3bfbe30a7814

Normalize static resource path early

6 files changed · +72 14
  • spring-webflux/src/main/java/org/springframework/web/reactive/function/server/PathResourceLookupFunction.java+18 5 modified
    @@ -104,7 +104,8 @@ public Mono<Resource> apply(ServerRequest request) {
     	protected String processPath(String path) {
     		path = StringUtils.replace(path, "\\", "/");
     		path = cleanDuplicateSlashes(path);
    -		return cleanLeadingSlash(path);
    +		path = cleanLeadingSlash(path);
    +		return normalizePath(path);
     	}
     
     	private String cleanDuplicateSlashes(String path) {
    @@ -146,6 +147,21 @@ else if (path.charAt(i) > ' ' && path.charAt(i) != 127) {
     		return (slash ? "/" : "");
     	}
     
    +	private static String normalizePath(String path) {
    +		if (path.contains("%")) {
    +			try {
    +				path = URLDecoder.decode(path, StandardCharsets.UTF_8);
    +			}
    +			catch (Exception ex) {
    +				return "";
    +			}
    +			if (path.contains("../")) {
    +				path = StringUtils.cleanPath(path);
    +			}
    +		}
    +		return path;
    +	}
    +
     	private boolean isInvalidPath(String path) {
     		if (path.contains("WEB-INF") || path.contains("META-INF")) {
     			return true;
    @@ -156,10 +172,7 @@ private boolean isInvalidPath(String path) {
     				return true;
     			}
     		}
    -		if (path.contains("..") && StringUtils.cleanPath(path).contains("../")) {
    -			return true;
    -		}
    -		return false;
    +		return path.contains("../");
     	}
     
     	/**
    
  • spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java+18 2 modified
    @@ -523,7 +523,8 @@ private String getResourcePath(ServerWebExchange exchange) {
     	protected String processPath(String path) {
     		path = StringUtils.replace(path, "\\", "/");
     		path = cleanDuplicateSlashes(path);
    -		return cleanLeadingSlash(path);
    +		path = cleanLeadingSlash(path);
    +		return normalizePath(path);
     	}
     
     	private String cleanDuplicateSlashes(String path) {
    @@ -565,6 +566,21 @@ else if (path.charAt(i) > ' ' && path.charAt(i) != 127) {
     		return (slash ? "/" : "");
     	}
     
    +	private static String normalizePath(String path) {
    +		if (path.contains("%")) {
    +			try {
    +				path = URLDecoder.decode(path, StandardCharsets.UTF_8);
    +			}
    +			catch (Exception ex) {
    +				return "";
    +			}
    +			if (path.contains("../")) {
    +				path = StringUtils.cleanPath(path);
    +			}
    +		}
    +		return path;
    +	}
    +
     	/**
     	 * Check whether the given path contains invalid escape sequences.
     	 * @param path the path to validate
    @@ -623,7 +639,7 @@ protected boolean isInvalidPath(String path) {
     				return true;
     			}
     		}
    -		if (path.contains("..") && StringUtils.cleanPath(path).contains("../")) {
    +		if (path.contains("../")) {
     			if (logger.isWarnEnabled()) {
     				logger.warn(LogFormatUtils.formatValue(
     						"Path contains \"../\" after call to StringUtils#cleanPath: [" + path + "]", -1, true));
    
  • spring-webflux/src/test/java/org/springframework/web/reactive/resource/ResourceWebHandlerTests.java+0 2 modified
    @@ -670,7 +670,6 @@ void shouldRejectInvalidPath() throws Exception {
     			testInvalidPath("/../.." + secretPath, handler);
     			testInvalidPath("/%2E%2E/testsecret/secret.txt", handler);
     			testInvalidPath("/%2E%2E/testsecret/secret.txt", handler);
    -			testInvalidPath("%2F%2F%2E%2E%2F%2F%2E%2E" + secretPath, handler);
     		}
     
     		private void testInvalidPath(String requestPath, ResourceWebHandler handler) {
    @@ -705,7 +704,6 @@ void resolvePathWithTraversal(HttpMethod method) throws Exception {
     			testResolvePathWithTraversal(method, "/url:" + secretPath);
     			testResolvePathWithTraversal(method, "////../.." + secretPath);
     			testResolvePathWithTraversal(method, "/%2E%2E/testsecret/secret.txt");
    -			testResolvePathWithTraversal(method, "%2F%2F%2E%2E%2F%2Ftestsecret/secret.txt");
     			testResolvePathWithTraversal(method, "url:" + secretPath);
     
     			// The following tests fail with a MalformedURLException on Windows
    
  • spring-webmvc/src/main/java/org/springframework/web/servlet/function/PathResourceLookupFunction.java+18 2 modified
    @@ -105,7 +105,8 @@ public Optional<Resource> apply(ServerRequest request) {
     	protected String processPath(String path) {
     		path = StringUtils.replace(path, "\\", "/");
     		path = cleanDuplicateSlashes(path);
    -		return cleanLeadingSlash(path);
    +		path = cleanLeadingSlash(path);
    +		return normalizePath(path);
     	}
     
     	private String cleanDuplicateSlashes(String path) {
    @@ -147,6 +148,21 @@ else if (path.charAt(i) > ' ' && path.charAt(i) != 127) {
     		return (slash ? "/" : "");
     	}
     
    +	private static String normalizePath(String path) {
    +		if (path.contains("%")) {
    +			try {
    +				path = URLDecoder.decode(path, StandardCharsets.UTF_8);
    +			}
    +			catch (Exception ex) {
    +				return "";
    +			}
    +			if (path.contains("../")) {
    +				path = StringUtils.cleanPath(path);
    +			}
    +		}
    +		return path;
    +	}
    +
     	private boolean isInvalidPath(String path) {
     		if (path.contains("WEB-INF") || path.contains("META-INF")) {
     			return true;
    @@ -157,7 +173,7 @@ private boolean isInvalidPath(String path) {
     				return true;
     			}
     		}
    -		return path.contains("..") && StringUtils.cleanPath(path).contains("../");
    +		return path.contains("../");
     	}
     
     	private boolean isInvalidEncodedInputPath(String path) {
    
  • spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java+18 2 modified
    @@ -682,7 +682,8 @@ private static String getPath(HttpServletRequest request) {
     	protected String processPath(String path) {
     		path = StringUtils.replace(path, "\\", "/");
     		path = cleanDuplicateSlashes(path);
    -		return cleanLeadingSlash(path);
    +		path = cleanLeadingSlash(path);
    +		return normalizePath(path);
     	}
     
     	private String cleanDuplicateSlashes(String path) {
    @@ -724,6 +725,21 @@ else if (path.charAt(i) > ' ' && path.charAt(i) != 127) {
     		return (slash ? "/" : "");
     	}
     
    +	private static String normalizePath(String path) {
    +		if (path.contains("%")) {
    +			try {
    +				path = URLDecoder.decode(path, StandardCharsets.UTF_8);
    +			}
    +			catch (Exception ex) {
    +				return "";
    +			}
    +			if (path.contains("../")) {
    +				path = StringUtils.cleanPath(path);
    +			}
    +		}
    +		return path;
    +	}
    +
     	/**
     	 * Check whether the given path contains invalid escape sequences.
     	 * @param path the path to validate
    @@ -783,7 +799,7 @@ protected boolean isInvalidPath(String path) {
     				return true;
     			}
     		}
    -		if (path.contains("..") && StringUtils.cleanPath(path).contains("../")) {
    +		if (path.contains("../")) {
     			if (logger.isWarnEnabled()) {
     				logger.warn(LogFormatUtils.formatValue(
     						"Path contains \"../\" after call to StringUtils#cleanPath: [" + path + "]", -1, true));
    
  • spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java+0 1 modified
    @@ -656,7 +656,6 @@ void shouldRejectInvalidPath() throws Exception {
     			testInvalidPath("/../.." + secretPath);
     			testInvalidPath("/%2E%2E/testsecret/secret.txt");
     			testInvalidPath("/%2E%2E/testsecret/secret.txt");
    -			testInvalidPath("%2F%2F%2E%2E%2F%2F%2E%2E" + secretPath);
     		}
     
     		private void testInvalidPath(String requestPath) {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.