volosied commented on code in PR #1043:
URL: https://github.com/apache/myfaces/pull/1043#discussion_r3798022353


##########
impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletFactory.java:
##########
@@ -248,34 +256,205 @@ public long getRefreshPeriod()
     }
 
     /**
-     * Resolves a path based on the passed URL. If the path starts with '/', 
then resolve the path against
-     * {@link 
jakarta.faces.context.ExternalContext#getResource(java.lang.String)
-     * jakarta.faces.context.ExternalContext#getResource(java.lang.String)}. 
Otherwise create a new URL via
-     * {@link URL#URL(java.net.URL, java.lang.String) URL(URL, String)}.
-     * 
-     * @param source
-     *            base to resolve from
-     * @param path
-     *            relative path to the source
+     * Resolves a path to a URL, validating scheme, traversal, and extension.
+     * Absolute paths (starting with '/') are resolved via ExternalContext;
+     * relative paths are resolved against the source URL.
+     * @param context FacesContext
+     * @param source base URL for relative resolution
+     * @param path path to resolve
      * @return resolved URL
-     * @throws IOException
+     * @throws IOException if path is invalid or not found
      */
     public URL resolveURL(FacesContext context, URL source, String path) 
throws IOException
     {
-        if (path.startsWith("/"))
+        if (!isAllowedScheme(path))
+        {
+            throw new 
InvalidFileException(InvalidFileException.Reason.DISALLOWED_SCHEME,
+                    "Remote or disallowed scheme in path: " + path);
+        }
+
+        URL resolved;
+        String normalizedPath;
+        boolean absoluteContextPath = path.startsWith("/");
+
+        if (absoluteContextPath)
         {
+            // Absolute context-relative path via ExternalContext (scoped to 
WAR by container)
             context.getAttributes().put(LAST_RESOURCE_RESOLVED, null);
-            URL url = resolveURL(context, path);
-            if (url == null)
+            resolved = resolveURL(context, path);
+            if (resolved == null)
             {
                 throw new FileNotFoundException(path + " Not Found in 
ExternalContext as a Resource");
             }
-            return url;
+            normalizedPath = path;
         }
         else
         {
-            return new URL(source, path);
+            // Relative path resolved against source URL
+            if (source == null)
+            {
+                // Fall back to ExternalContext if no base URL available
+                resolved = resolveURL(context, path);
+                if (resolved == null)
+                {
+                    throw new FileNotFoundException("Cannot resolve relative 
path '" + path);
+                }
+                normalizedPath = path;
+            }
+            else
+            {
+                resolved = new URL(source, path);
+                normalizedPath = resolved.getPath();
+            }
+        }
+
+        // Skip validation in UnitTest stage (uses synthetic paths)
+        if (context.isProjectStage(ProjectStage.UnitTest))
+        {
+            return resolved;
+        }
+
+        // Traversal guard: relative paths must stay within base (absolute 
paths already scoped by container)
+        if (!absoluteContextPath && source != null && !isWithinBase(resolved))
+        {
+            throw new 
InvalidFileException(InvalidFileException.Reason.PATH_TRAVERSAL,
+                    "Path escapes application base: " + path);
+        }
+
+        // Extension must be a configured Facelet suffix
+        if (!mappingAllowed(context, normalizedPath))
+        {
+            throw new 
InvalidFileException(InvalidFileException.Reason.INVALID_EXTENSION,
+                    "Invalid path provided: " + path);
+        }
+
+        return resolved;
+    }
+
+    // Path-validation helpers
+
+    private static final Set<String> BLOCKED_SCHEMES = new HashSet<>(
+            Arrays.asList("http", "https", "ftp", "ftps", "mailto", "tel",

Review Comment:
   Fixed!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to