This is an automated email from the ASF dual-hosted git repository.
jacopoc pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push:
new cefbdb21ea Fixed: Add validation for product image file names in
renameImage to prevent path traversal
cefbdb21ea is described below
commit cefbdb21eabb4afd56a7aa0a9d77ebcc55738fff
Author: Jacopo Cappellato <[email protected]>
AuthorDate: Mon Jul 27 18:40:43 2026 +0200
Fixed: Add validation for product image file names in renameImage to
prevent path traversal
---
.../imagemanagement/ImageManagementServices.java | 31 ++++++++++++++++++++++
1 file changed, 31 insertions(+)
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 25993c5976..3cf4284464 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
@@ -27,6 +27,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
@@ -72,6 +73,28 @@ public class ImageManagementServices {
private static int imageCount = 0;
private static String imagePath;
+ /**
+ * Ensures a user-supplied image file name is safe to use as a rename
target: it must pass
+ * {@link org.apache.ofbiz.security.SecuredUpload#isValidFileName} (no
path separators, no
+ * 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) {
+ if (UtilValidate.isEmpty(fileName)) {
+ return false;
+ }
+ try {
+ if
(!org.apache.ofbiz.security.SecuredUpload.isValidFileName(fileName, delegator))
{
+ return false;
+ }
+ Path resolvedFilePath =
resolvedProductDir.resolve(fileName).normalize();
+ return resolvedFilePath.getParent() != null &&
resolvedFilePath.getParent().equals(resolvedProductDir);
+ } catch (IOException | InvalidPathException e) {
+ Debug.logError(e, MODULE);
+ return false;
+ }
+ }
+
public static Map<String, Object>
addMultipleuploadForProduct(DispatchContext dctx,
Map<String, ? extends Object> context) throws ImageReadException {
@@ -890,6 +913,14 @@ public class ImageManagementServices {
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"ProductImageViewUnableWriteFile",
UtilMisc.toMap("fileName", resolvedProductDir.toString()), locale));
}
+ // Guard against path traversal via drDataResourceName: it must
resolve to a plain file name
+ // directly inside the product's own image directory, with no
separators or traversal sequences,
+ // and a supported image extension.
+ if (!isValidProductImageFileName(filenameToUse, resolvedProductDir,
delegator)) {
+ Debug.logError("Path traversal attempt detected in rename image,
drDataResourceName: " + filenameToUse, MODULE);
+ return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
+ "ProductImageViewUnableWriteFile",
UtilMisc.toMap("fileName", filenameToUse), locale));
+ }
String imageType =
filenameToUse.substring(filenameToUse.lastIndexOf('.'));
String imgExtension = filenameToUse.substring(filenameToUse.length() -
3, filenameToUse.length());
String imageUrl = imageServerUrl + "/" + productId + "/" +
filenameToUse;