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));