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

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 74644fbf1a fix: Add decompression size limits to 
ZipUtil.unzip()[#6400] (#6416)
74644fbf1a is described below

commit 74644fbf1a5873810fd5e4377f7690ca8a520c76
Author: hengyuss <[email protected]>
AuthorDate: Mon Jul 6 15:38:56 2026 +0800

    fix: Add decompression size limits to ZipUtil.unzip()[#6400] (#6416)
    
    * fix: Add decompression size limits to ZipUtil.unzip()[#6400]
    
    * fix: fix checkStyle
    
    * fix: fix test
    
    * fix: remove magic num in ConfigServiceTest.java
    
    ---------
    
    Co-authored-by: aias00 <[email protected]>
---
 .../admin/service/impl/ConfigsServiceImpl.java     | 23 ++++++++++-
 .../org/apache/shenyu/admin/utils/ZipUtil.java     | 44 +++++++++++++++++++++-
 shenyu-admin/src/main/resources/application.yml    |  6 +++
 .../shenyu/admin/service/ConfigsServiceTest.java   | 10 +++++
 4 files changed, 79 insertions(+), 4 deletions(-)

diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ConfigsServiceImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ConfigsServiceImpl.java
index 99842dc26a..5e4e65c592 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ConfigsServiceImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ConfigsServiceImpl.java
@@ -64,6 +64,7 @@ import org.apache.shenyu.common.utils.JsonUtils;
 import org.apache.shenyu.common.utils.ListUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.Comparator;
@@ -79,6 +80,24 @@ public class ConfigsServiceImpl implements ConfigsService {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(ConfigsServiceImpl.class);
 
+    /**
+     * The max entry size for unzip.
+     */
+    @Value("${shenyu.config.import.max-entry-size:104857600}")
+    private long maxEntrySize;
+
+    /**
+     * The max total size for unzip.
+     */
+    @Value("${shenyu.config.import.max-total-size:209715200}")
+    private long maxTotalSize;
+
+    /**
+     * The max entry count for unzip.
+     */
+    @Value("${shenyu.config.import.max-entry-count:1000}")
+    private int maxEntryCount;
+
     /**
      * The AppAuth service.
      */
@@ -342,7 +361,7 @@ public class ConfigsServiceImpl implements ConfigsService {
 
     @Override
     public ShenyuAdminResult configsImport(final byte[] source) {
-        ZipUtil.UnZipResult unZipResult = ZipUtil.unzip(source);
+        ZipUtil.UnZipResult unZipResult = ZipUtil.unzip(source, maxEntrySize, 
maxTotalSize, maxEntryCount);
         List<ZipUtil.ZipItem> zipItemList = unZipResult.getZipItemList();
         if (CollectionUtils.isEmpty(zipItemList)) {
             LOG.info("import file is empty");
@@ -387,7 +406,7 @@ public class ConfigsServiceImpl implements ConfigsService {
     
     @Override
     public ShenyuAdminResult configsImport(final String namespace, final 
byte[] source) {
-        ZipUtil.UnZipResult unZipResult = ZipUtil.unzip(source);
+        ZipUtil.UnZipResult unZipResult = ZipUtil.unzip(source, maxEntrySize, 
maxTotalSize, maxEntryCount);
         List<ZipUtil.ZipItem> zipItemList = unZipResult.getZipItemList();
         if (CollectionUtils.isEmpty(zipItemList)) {
             LOG.info("import file is empty");
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/ZipUtil.java 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/ZipUtil.java
index 5dda4bed3b..16f8cf7b54 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/ZipUtil.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/ZipUtil.java
@@ -38,10 +38,21 @@ public final class ZipUtil {
 
     private static final Logger LOG = LoggerFactory.getLogger(ZipUtil.class);
 
+    /**
+     * 100 MB per entry.
+     */
+    private static final long MAX_ENTRY_SIZE = 100L * 1024 * 1024;
+
+    /**
+     * 200 MB total.
+     */
+    private static final long MAX_TOTAL_SIZE = 200L * 1024 * 1024;
+
+    private static final int MAX_ENTRY_COUNT = 1000;
+
     private ZipUtil() {
     }
 
-
     /**
      * zip method.
      *
@@ -66,23 +77,52 @@ public final class ZipUtil {
     }
 
     /**
-     * unzip method.
+     * unzip method with default size limits.
      *
      * @param source source
      * @return unzip result
      */
     public static UnZipResult unzip(final byte[] source) {
+        return unzip(source, MAX_ENTRY_SIZE, MAX_TOTAL_SIZE, MAX_ENTRY_COUNT);
+    }
+
+    /**
+     * unzip method with configurable size limits.
+     *
+     * @param source source
+     * @param maxEntrySize max entry size
+     * @param maxTotalSize max total size
+     * @param maxEntryCount max entry count
+     * @return unzip result
+     */
+    public static UnZipResult unzip(final byte[] source, final long 
maxEntrySize,
+                                    final long maxTotalSize, final int 
maxEntryCount) {
         List<ZipItem> itemList = Lists.newArrayList();
+        long totalSize = 0L;
+        int entryCount = 0;
         try (ZipInputStream zipIn = new ZipInputStream(new 
ByteArrayInputStream(source))) {
             ZipEntry entry;
             while (Objects.nonNull(entry = zipIn.getNextEntry())) {
                 if (entry.isDirectory()) {
                     continue;
                 }
+                entryCount++;
+                if (entryCount > maxEntryCount) {
+                    throw new IllegalArgumentException("entry count exceeds 
maximum of " + maxEntryCount);
+                }
                 try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
                     byte[] buffer = new byte[1024];
                     int offset;
+                    long entrySize = 0L;
                     while ((offset = zipIn.read(buffer)) != -1) {
+                        entrySize += offset;
+                        totalSize += offset;
+                        if (entrySize > maxEntrySize) {
+                            throw new IllegalArgumentException("entry size 
exceeds maximum allowed value.");
+                        }
+                        if (totalSize > maxTotalSize) {
+                            throw new IllegalArgumentException("total size 
exceeds maximum allowed value.");
+                        }
                         out.write(buffer, 0, offset);
                     }
                     String entryName = entry.getName();
diff --git a/shenyu-admin/src/main/resources/application.yml 
b/shenyu-admin/src/main/resources/application.yml
index 0e986c0c0a..a0850d0bea 100755
--- a/shenyu-admin/src/main/resources/application.yml
+++ b/shenyu-admin/src/main/resources/application.yml
@@ -227,6 +227,11 @@ shenyu:
       apiServer: "https://127.0.0.1:6443";
       token: "token"
       caCertPath: "/etc/kubernetes/pki/ca.crt"
+  config:
+    import:
+      max-entry-size: 104857600
+      max-total-size: 209715200
+      max-entry-count: 1000
 
 springdoc:
   api-docs:
@@ -246,3 +251,4 @@ logging:
     org.apache.shenyu.lottery: info
     org.apache.shenyu: info
 #    org.apache.shenyu.admin.utils.HttpUtils: debug
+
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ConfigsServiceTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ConfigsServiceTest.java
index b8023af730..b113f75b31 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ConfigsServiceTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ConfigsServiceTest.java
@@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Collections;
 import java.util.List;
@@ -45,6 +46,12 @@ import static org.mockito.Mockito.when;
 @ExtendWith(MockitoExtension.class)
 public final class ConfigsServiceTest {
 
+    private static final long MAX_ENTRY_SIZE = 100L * 1024 * 1024;
+
+    private static final long MAX_TOTAL_SIZE = 200L * 1024 * 1024;
+
+    private static final int MAX_ENTRY_COUNT = 1000;
+
     private ConfigsServiceImpl configsService;
 
     @Mock
@@ -84,6 +91,9 @@ public final class ConfigsServiceTest {
     public void setUp() {
         configsService = new ConfigsServiceImpl(appAuthService, pluginService, 
namespacePluginService, pluginHandleService, selectorService, ruleService,
                 metaDataService, shenyuDictService, proxySelectorService, 
discoveryService, discoveryUpstreamService, Collections.emptyList());
+        ReflectionTestUtils.setField(configsService, "maxEntrySize", 
MAX_ENTRY_SIZE);
+        ReflectionTestUtils.setField(configsService, "maxTotalSize", 
MAX_TOTAL_SIZE);
+        ReflectionTestUtils.setField(configsService, "maxEntryCount", 
MAX_ENTRY_COUNT);
     }
 
     @Test

Reply via email to