This is an automated email from the ASF dual-hosted git repository.

mridulpathak pushed a commit to branch release24.09
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/release24.09 by this push:
     new e51ba7984a Improved: Add validation and permission check to 
replaceImageToExistImage service
e51ba7984a is described below

commit e51ba7984aefd9e944315ce116aa137d337b21d5
Author: Mridul Pathak <[email protected]>
AuthorDate: Tue Aug 18 13:04:08 2026 +0530

    Improved: Add validation and permission check to replaceImageToExistImage 
service
    
    Backported from trunk (#1671).
---
 .../product/config/ProductErrorUiLabels.xml        |  3 +++
 .../imagemanagement/ImageManagementServices.java   |  2 +-
 .../product/imagemanagement/ReplaceImage.java      | 26 ++++++++++++++++++++++
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/applications/product/config/ProductErrorUiLabels.xml 
b/applications/product/config/ProductErrorUiLabels.xml
index a0e87f1dc4..0906a9d058 100644
--- a/applications/product/config/ProductErrorUiLabels.xml
+++ b/applications/product/config/ProductErrorUiLabels.xml
@@ -183,6 +183,9 @@
     <property key="ProductCannotReplaceImage">
         <value xml:lang="en">Cannot replace image.</value>
     </property>
+    <property key="ProductImageManagementPermissionError">
+        <value xml:lang="en">You do not have permission to manage images 
("IMAGE_MANAGEMENT_ADMIN" needed).</value>
+    </property>
     <property key="ProductCreateCommunicationEventProductPermissionError">
         <value xml:lang="de">Berechtigungsfehler beim Erstellen des Produkt 
Communication Events</value>
         <value xml:lang="en">Create Communication Event Product Permission 
Error</value>
diff --git 
a/applications/product/src/main/java/org/apache/ofbiz/product/imagemanagement/ImageManagementServices.java
 
b/applications/product/src/main/java/org/apache/ofbiz/product/imagemanagement/ImageManagementServices.java
index 5ca3b619d8..36616c1937 100644
--- 
a/applications/product/src/main/java/org/apache/ofbiz/product/imagemanagement/ImageManagementServices.java
+++ 
b/applications/product/src/main/java/org/apache/ofbiz/product/imagemanagement/ImageManagementServices.java
@@ -79,7 +79,7 @@ public class ImageManagementServices {
      * traversal sequences, no denied extensions) and must resolve, once 
normalized, directly
      * inside the given product image directory.
      */
-    private static boolean isValidProductImageFileName(String fileName, Path 
resolvedProductDir, Delegator delegator) {
+    static boolean isValidProductImageFileName(String fileName, Path 
resolvedProductDir, Delegator delegator) {
         if (UtilValidate.isEmpty(fileName)) {
             return false;
         }
diff --git 
a/applications/product/src/main/java/org/apache/ofbiz/product/imagemanagement/ReplaceImage.java
 
b/applications/product/src/main/java/org/apache/ofbiz/product/imagemanagement/ReplaceImage.java
index 12a68bd875..1420635dcb 100644
--- 
a/applications/product/src/main/java/org/apache/ofbiz/product/imagemanagement/ReplaceImage.java
+++ 
b/applications/product/src/main/java/org/apache/ofbiz/product/imagemanagement/ReplaceImage.java
@@ -21,6 +21,8 @@ package org.apache.ofbiz.product.imagemanagement;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -29,6 +31,7 @@ import java.util.Map;
 import javax.imageio.ImageIO;
 
 import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.UtilMisc;
 import org.apache.ofbiz.base.util.UtilProperties;
 import org.apache.ofbiz.base.util.UtilValidate;
 import org.apache.ofbiz.base.util.string.FlexibleStringExpander;
@@ -37,6 +40,7 @@ import org.apache.ofbiz.entity.GenericEntityException;
 import org.apache.ofbiz.entity.GenericValue;
 import org.apache.ofbiz.entity.util.EntityQuery;
 import org.apache.ofbiz.entity.util.EntityUtilProperties;
+import org.apache.ofbiz.security.Security;
 import org.apache.ofbiz.service.DispatchContext;
 import org.apache.ofbiz.service.GenericServiceException;
 import org.apache.ofbiz.service.LocalDispatcher;
@@ -61,6 +65,13 @@ public class ReplaceImage {
         String dataResourceNameExist = (String) 
context.get("dataResourceNameExist");
         String dataResourceNameReplace = (String) 
context.get("dataResourceNameReplace");
 
+        Security security = dctx.getSecurity();
+        if (!security.hasPermission("IMAGE_MANAGEMENT_ADMIN", userLogin)) {
+            String errMsg = UtilProperties.getMessage(RES_ERROR, 
"ProductImageManagementPermissionError", locale);
+            Debug.logError(errMsg, MODULE);
+            return ServiceUtil.returnError(errMsg);
+        }
+
         if (UtilValidate.isNotEmpty(dataResourceNameExist)) {
             if (UtilValidate.isNotEmpty(contentIdReplace)) {
                 if (contentIdExist.equals(contentIdReplace)) {
@@ -79,6 +90,21 @@ public class ReplaceImage {
             return ServiceUtil.returnError(errMsg);
         }
 
+        Path imageServerNormalizedPath = 
Paths.get(imageServerPath).normalize();
+        Path resolvedProductDir = Paths.get(imageServerPath, 
productId).normalize();
+        if (!resolvedProductDir.startsWith(imageServerNormalizedPath)) {
+            Debug.logError("Path traversal attempt detected in replace image, 
productId: " + productId, MODULE);
+            return ServiceUtil.returnError(UtilProperties.getMessage(RESOURCE,
+                    "ProductImageViewUnableWriteFile", 
UtilMisc.toMap("fileName", resolvedProductDir.toString()), locale));
+        }
+        if 
(!ImageManagementServices.isValidProductImageFileName(dataResourceNameReplace, 
resolvedProductDir, delegator)
+                || 
!ImageManagementServices.isValidProductImageFileName(dataResourceNameExist, 
resolvedProductDir, delegator)) {
+            Debug.logError("Path traversal attempt detected in replace image, 
dataResourceNameReplace: " + dataResourceNameReplace
+                    + ", dataResourceNameExist: " + dataResourceNameExist, 
MODULE);
+            return ServiceUtil.returnError(UtilProperties.getMessage(RESOURCE,
+                    "ProductImageViewUnableWriteFile", 
UtilMisc.toMap("fileName", dataResourceNameExist), locale));
+        }
+
         try {
             BufferedImage bufImg = ImageIO.read(new File(imageServerPath + "/" 
+ productId + "/" + dataResourceNameReplace));
             ImageIO.write(bufImg, "jpg", new File(imageServerPath + "/" + 
productId + "/" + dataResourceNameExist));

Reply via email to