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

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


The following commit(s) were added to refs/heads/master by this push:
     new 07fd5b25c3 [improve] improve plugin upload validation (#4067)
07fd5b25c3 is described below

commit 07fd5b25c3dd27bc4def8a4c462c1a3d8b6d6b85
Author: Duansg <[email protected]>
AuthorDate: Tue Mar 17 09:14:38 2026 +0800

    [improve] improve plugin upload validation (#4067)
---
 .github/workflows/backend-build-test.yml           |  1 +
 .../manager/service/impl/PluginServiceImpl.java    |  4 +++
 .../manager/service/PluginServiceTest.java         | 34 ++++++++++++++++++++++
 3 files changed, 39 insertions(+)

diff --git a/.github/workflows/backend-build-test.yml 
b/.github/workflows/backend-build-test.yml
index 34917e8e50..bac52c86cb 100644
--- a/.github/workflows/backend-build-test.yml
+++ b/.github/workflows/backend-build-test.yml
@@ -52,6 +52,7 @@ jobs:
         uses: codecov/[email protected]
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
+          fail_ci_if_error: false
           verbose: true
 
       - name: Build Image
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/PluginServiceImpl.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/PluginServiceImpl.java
index 963275738c..a8206b35bf 100644
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/PluginServiceImpl.java
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/PluginServiceImpl.java
@@ -490,6 +490,10 @@ public class PluginServiceImpl implements PluginService {
             while (entries.hasMoreElements()) {
                 JarEntry entry = entries.nextElement();
                 File file = new File(libDir, entry.getName());
+                String canonicalLibDir = libDir.getCanonicalPath() + 
File.separator;
+                if (!file.getCanonicalPath().startsWith(canonicalLibDir)) {
+                    throw new IOException("Zip Slip detected: " + 
entry.getName());
+                }
                 if (entry.isDirectory()) {
                     continue;
                 }
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/PluginServiceTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/PluginServiceTest.java
index fef26765d3..5c3181c914 100644
--- 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/PluginServiceTest.java
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/PluginServiceTest.java
@@ -19,7 +19,9 @@ package org.apache.hertzbeat.manager.service;
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -30,12 +32,18 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Method;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
 import org.apache.hertzbeat.common.constants.PluginType;
 import org.apache.hertzbeat.common.entity.manager.PluginItem;
 import org.apache.hertzbeat.common.entity.manager.PluginMetadata;
@@ -48,6 +56,7 @@ import 
org.apache.hertzbeat.manager.service.impl.PluginServiceImpl;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
@@ -159,4 +168,29 @@ class PluginServiceTest {
         verify(metadataDao, times(1)).findAll(any(Specification.class), 
any(PageRequest.class));
     }
 
+    @Test
+    void testZipSlipDetected(@TempDir File tempDir) throws Exception {
+        File maliciousJar = new File(tempDir, "malicious.jar");
+        try (JarOutputStream jos = new JarOutputStream(new 
FileOutputStream(maliciousJar))) {
+            JarEntry evilEntry = new JarEntry("../../evil.jar");
+            jos.putNextEntry(evilEntry);
+            jos.write("malicious-content".getBytes(StandardCharsets.UTF_8));
+            jos.closeEntry();
+        }
+        Method method = PluginServiceImpl.class.getDeclaredMethod(
+            "loadLibInPlugin", String.class, Long.class);
+        method.setAccessible(true);
+
+        Exception exception = assertThrows(Exception.class, () -> {
+            try {
+                method.invoke(pluginService, maliciousJar.getAbsolutePath(), 
1L);
+            } catch (java.lang.reflect.InvocationTargetException e) {
+                throw e.getCause();
+            }
+        });
+
+        assertInstanceOf(IOException.class, exception);
+        assertTrue(exception.getMessage().contains("Zip Slip detected"));
+    }
+
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to