CVE-2018-17605: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') (CWE-22)
value: An issue was discovered in the Asset Pipeline plugin before 3.0.4 for Grails. An attacker can perform directory traversal via a crafted request when a servlet-based application is executed in Jetty, because there is a classloader vulnerability that can allow a reverse file traversal route in AssetPipelineFilter.groovy or AssetPipelineFilterCore.groovy.
CWE description: The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
CVSS v3 base score: 7.5
Published: 2018-09-28T09:29Z
Repository: https://github.com/bertramdev/asset-pipeline
Language: Other
Files changed: asset-pipeline-grails/src/main/groovy/asset/pipeline/AssetPipelineFilter.groovy, asset-pipeline-servlet/src/main/groovy/asset/pipeline/servlet/AssetPipelineFilterCore.groovy, build.gradle
Commit date: 2018-08-22 13:23:55 -0400
Commit message: fixing jetty classloader vulnerability with potential reverse file traverse route when running servlet based apps in jetty

Diff: diff --git a/asset-pipeline-grails/src/main/groovy/asset/pipeline/AssetPipelineFilter.groovy b/asset-pipeline-grails/src/main/groovy/asset/pipeline/AssetPipelineFilter.groovy
index af56827..cb401c9 100644
--- a/asset-pipeline-grails/src/main/groovy/asset/pipeline/AssetPipelineFilter.groovy
+++ b/asset-pipeline-grails/src/main/groovy/asset/pipeline/AssetPipelineFilter.groovy
@@ -2,10 +2,11 @@ package asset.pipeline
 
 
 import asset.pipeline.grails.AssetAttributes
 import asset.pipeline.grails.AssetProcessorService
 import asset.pipeline.grails.ProductionAssetCache
+import asset.pipeline.AssetHelper
 import groovy.transform.CompileStatic
 import groovy.util.logging.Commons
 import javax.servlet.FilterChain
 import javax.servlet.FilterConfig
 import javax.servlet.ServletContext
@@ -61,11 +62,11 @@ class AssetPipelineFilter extends OncePerRequestFilter {
 				fileUri += indexFile
 			}
 			if(fileUri.startsWith('/')) {
 				manifestPath = fileUri.substring(1) //Omit forward slash
 			}
-
+			fileUri = AssetHelper.normalizePath(fileUri) //JETTY Security bug, we MUST prevent reverse traversal
 			fileUri = manifest?.getProperty(manifestPath, manifestPath)
 
 
 
 			final AssetAttributes attributeCache = fileCache.get(fileUri)
diff --git a/asset-pipeline-servlet/src/main/groovy/asset/pipeline/servlet/AssetPipelineFilterCore.groovy b/asset-pipeline-servlet/src/main/groovy/asset/pipeline/servlet/AssetPipelineFilterCore.groovy
index 3bb7c80..34cc219 100644
--- a/asset-pipeline-servlet/src/main/groovy/asset/pipeline/servlet/AssetPipelineFilterCore.groovy
+++ b/asset-pipeline-servlet/src/main/groovy/asset/pipeline/servlet/AssetPipelineFilterCore.groovy
@@ -1,10 +1,11 @@
 package asset.pipeline.servlet
 
 
 import asset.pipeline.AssetPipelineResponseBuilder
 import asset.pipeline.AssetPipelineConfigHolder
+import asset.pipeline.AssetHelper
 import java.util.logging.Logger
 import javax.servlet.FilterChain
 import javax.servlet.ServletContext
 import javax.servlet.ServletException
 import javax.servlet.ServletOutputStream
@@ -41,10 +42,11 @@ class AssetPipelineFilterCore {
 		String fileUri = request.requestURI
 		final String baseAssetUrl = request.contextPath == "/" ? "/$mapping" : "${request.contextPath}/${mapping}"
 		if(fileUri.startsWith(baseAssetUrl)) {
 			fileUri = fileUri.substring(baseAssetUrl.length())
 		}
+		fileUri = AssetHelper.normalizePath(fileUri) //JETTY Security bug, we MUST prevent reverse 
 		final Properties manifest = AssetPipelineConfigHolder.manifest
 		String manifestPath = fileUri
 		if(fileUri.startsWith('/')) {
 			manifestPath = fileUri.substring(1) //Omit forward slash
 		}
diff --git a/build.gradle b/build.gradle
index 523a8a9..7459e3c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,11 +6,11 @@ buildscript {
 	dependencies {
 	}
 }
 
 subprojects {
-	version = '3.0.3'
+	version = '3.0.4'
 }
 
 apply plugin: 'groovy'
 apply plugin: 'idea'
 

Vulnerable code: 
	version = '3.0.3'
Fixed code: import asset.pipeline.AssetHelper
			fileUri = AssetHelper.normalizePath(fileUri) //JETTY Security bug, we MUST prevent reverse traversal
import asset.pipeline.AssetHelper
		fileUri = AssetHelper.normalizePath(fileUri) //JETTY Security bug, we MUST prevent reverse 
	version = '3.0.4'