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

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


The following commit(s) were added to refs/heads/master by this push:
     new 20ce15e04a5 Fix fail-open authorization for pipe config plans (#18488)
20ce15e04a5 is described below

commit 20ce15e04a56f37ad7721c95f023a3adf3f467a0
Author: Caideyipi <[email protected]>
AuthorDate: Mon Aug 24 12:28:58 2026 +0800

    Fix fail-open authorization for pipe config plans (#18488)
    
    * Fix fail-open authorization for pipe config plans
    
    * Fix pipe device deletion authorization
    
    * Harden pipe plugin path handling
    
    * Fix pipe plugin metadata test import
    
    * Deduplicate pipe plugin path validation
---
 .../iotdb/pipe/it/single/IoTDBPipeReceiverIT.java  |  19 ++++
 .../receiver/protocol/IoTDBConfigNodeReceiver.java |  21 +++-
 .../pipe/agent/plugin/meta/PipePluginMeta.java     |  13 ++-
 .../service/PipePluginExecutableManager.java       |  60 +++++++----
 .../org/apache/iotdb/commons/utils/FileUtils.java  |  16 +++
 .../service/PipePluginExecutableManagerTest.java   | 111 +++++++++++++++++++++
 .../pipe/plugin/meta/PipePluginMetaTest.java       |  17 ++++
 7 files changed, 234 insertions(+), 23 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/pipe/it/single/IoTDBPipeReceiverIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/pipe/it/single/IoTDBPipeReceiverIT.java
index 5ca62ebb15f..136943f00b0 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/pipe/it/single/IoTDBPipeReceiverIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/pipe/it/single/IoTDBPipeReceiverIT.java
@@ -24,12 +24,15 @@ import 
org.apache.iotdb.commons.client.property.ThriftClientProperty;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
 import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.commons.path.MeasurementPath;
+import org.apache.iotdb.commons.pipe.agent.plugin.meta.PipePluginMeta;
 import org.apache.iotdb.commons.pipe.sink.client.IoTDBSyncClient;
 import 
org.apache.iotdb.commons.pipe.sink.payload.thrift.common.PipeTransferHandshakeConstant;
 import 
org.apache.iotdb.commons.pipe.sink.payload.thrift.request.IoTDBSinkRequestVersion;
 import 
org.apache.iotdb.commons.pipe.sink.payload.thrift.request.PipeRequestType;
+import 
org.apache.iotdb.confignode.consensus.request.write.pipe.plugin.CreatePipePluginPlan;
 import 
org.apache.iotdb.confignode.manager.pipe.sink.payload.PipeTransferConfigNodeHandshakeV1Req;
 import 
org.apache.iotdb.confignode.manager.pipe.sink.payload.PipeTransferConfigNodeHandshakeV2Req;
+import 
org.apache.iotdb.confignode.manager.pipe.sink.payload.PipeTransferConfigPlanReq;
 import 
org.apache.iotdb.db.pipe.sink.payload.evolvable.request.PipeTransferDataNodeHandshakeV1Req;
 import 
org.apache.iotdb.db.pipe.sink.payload.evolvable.request.PipeTransferDataNodeHandshakeV2Req;
 import 
org.apache.iotdb.db.pipe.sink.payload.evolvable.request.PipeTransferTabletRawReq;
@@ -56,6 +59,7 @@ import 
org.apache.iotdb.service.rpc.thrift.TSyncTransportMetaInfo;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.external.commons.io.FileUtils;
 import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.ReadWriteIOUtils;
 import org.apache.tsfile.write.record.Tablet;
 import org.apache.tsfile.write.schema.MeasurementSchema;
@@ -256,6 +260,21 @@ public class IoTDBPipeReceiverIT {
       Assert.assertNotEquals(
           TSStatusCode.NOT_LOGIN.getStatusCode(),
           
client.pipeTransfer(buildEmptyConfigPlanReq()).getStatus().getCode());
+      Assert.assertEquals(
+          TSStatusCode.NO_PERMISSION.getStatusCode(),
+          client
+              .pipeTransfer(
+                  PipeTransferConfigPlanReq.toTPipeTransferReq(
+                      new CreatePipePluginPlan(
+                          new PipePluginMeta(
+                              "receiver-security-test-plugin",
+                              "attacker.Plugin",
+                              false,
+                              "attacker.jar",
+                              "deadbeef"),
+                          new Binary(new byte[] {1}))))
+              .getStatus()
+              .getCode());
     }
   }
 
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/receiver/protocol/IoTDBConfigNodeReceiver.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/receiver/protocol/IoTDBConfigNodeReceiver.java
index 281867d0ec5..d76a1d2943c 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/receiver/protocol/IoTDBConfigNodeReceiver.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/receiver/protocol/IoTDBConfigNodeReceiver.java
@@ -88,6 +88,7 @@ import 
org.apache.iotdb.confignode.consensus.request.write.table.view.SetViewCom
 import 
org.apache.iotdb.confignode.consensus.request.write.table.view.SetViewPropertiesPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.template.CommitSetSchemaTemplatePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.template.CreateSchemaTemplatePlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.template.DropSchemaTemplatePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.template.ExtendSchemaTemplatePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.trigger.DeleteTriggerInTablePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.trigger.UpdateTriggerStateInTablePlan;
@@ -413,6 +414,12 @@ public class IoTDBConfigNodeReceiver extends 
IoTDBFileReceiver {
       case CreateSchemaTemplate:
         templateName = ((CreateSchemaTemplatePlan) 
plan).getTemplate().getName();
         return checkGlobalStatus(userEntity, PrivilegeType.SYSTEM, 
templateName, true);
+      case DropSchemaTemplate:
+        return checkGlobalStatus(
+            userEntity,
+            PrivilegeType.SYSTEM,
+            ((DropSchemaTemplatePlan) plan).getTemplateName(),
+            true);
       case CommitSetSchemaTemplate:
         templateName = ((CommitSetSchemaTemplatePlan) plan).getName();
         return checkGlobalStatus(userEntity, PrivilegeType.SYSTEM, 
templateName, true);
@@ -552,6 +559,12 @@ public class IoTDBConfigNodeReceiver extends 
IoTDBFileReceiver {
             PrivilegeType.DELETE,
             ((CommitDeleteTablePlan) plan).getDatabase(),
             ((CommitDeleteTablePlan) plan).getTableName());
+      case PipeDeleteDevices:
+        return checkTableStatus(
+            userEntity,
+            PrivilegeType.DELETE,
+            ((PipeDeleteDevicesPlan) plan).getDatabase(),
+            ((PipeDeleteDevicesPlan) plan).getTableName());
       case GrantRole:
       case GrantUser:
       case RevokeUser:
@@ -747,7 +760,7 @@ public class IoTDBConfigNodeReceiver extends 
IoTDBFileReceiver {
         return checkGlobalStatus(
             userEntity, PrivilegeType.MANAGE_ROLE, ((AuthorPlan) 
plan).getRoleName(), true);
       default:
-        return StatusUtils.OK;
+        return RpcUtils.getStatus(TSStatusCode.NO_PERMISSION);
     }
   }
 
@@ -1204,10 +1217,14 @@ public class IoTDBConfigNodeReceiver extends 
IoTDBFileReceiver {
             .getPermissionManager()
             .operatePermission((AuthorPlan) plan, 
shouldMarkAsPipeRequest.get());
       case CreateSchemaTemplate:
-      default:
+      case DropSchemaTemplate:
+        // Only explicitly supported config-region pipe plans may be written 
to consensus. New plan
+        // types must be added to an explicit case after their authorization 
is implemented.
         return configManager
             .getConsensusManager()
             .write(shouldMarkAsPipeRequest.get() ? new PipeEnrichedPlan(plan) 
: plan);
+      default:
+        return RpcUtils.getStatus(TSStatusCode.NO_PERMISSION);
     }
   }
 
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/plugin/meta/PipePluginMeta.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/plugin/meta/PipePluginMeta.java
index 19f6863be3c..dce904b532b 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/plugin/meta/PipePluginMeta.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/plugin/meta/PipePluginMeta.java
@@ -19,6 +19,8 @@
 
 package org.apache.iotdb.commons.pipe.agent.plugin.meta;
 
+import org.apache.iotdb.commons.utils.FileUtils;
+
 import org.apache.tsfile.utils.PublicBAOS;
 import org.apache.tsfile.utils.ReadWriteIOUtils;
 
@@ -26,6 +28,7 @@ import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
+import java.util.Locale;
 import java.util.Objects;
 
 public class PipePluginMeta {
@@ -52,22 +55,24 @@ public class PipePluginMeta {
       String jarName,
       String jarMD5,
       String pluginLoadingExceptionMessage) {
-    this.pluginName = Objects.requireNonNull(pluginName).toUpperCase();
+    this.pluginName =
+        
FileUtils.validatePathSegment(Objects.requireNonNull(pluginName)).toUpperCase(Locale.ROOT);
     this.className = Objects.requireNonNull(className);
 
     this.isBuiltin = isBuiltin;
     if (isBuiltin) {
-      this.jarName = jarName;
+      this.jarName = jarName == null ? null : 
FileUtils.validatePathSegment(jarName);
       this.jarMD5 = jarMD5;
     } else {
-      this.jarName = Objects.requireNonNull(jarName);
+      this.jarName = 
FileUtils.validatePathSegment(Objects.requireNonNull(jarName));
       this.jarMD5 = Objects.requireNonNull(jarMD5);
     }
     this.pluginLoadingExceptionMessage = pluginLoadingExceptionMessage;
   }
 
   public PipePluginMeta(String pluginName, String className) {
-    this.pluginName = Objects.requireNonNull(pluginName).toUpperCase();
+    this.pluginName =
+        
FileUtils.validatePathSegment(Objects.requireNonNull(pluginName)).toUpperCase(Locale.ROOT);
     this.className = Objects.requireNonNull(className);
 
     this.isBuiltin = true;
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/plugin/service/PipePluginExecutableManager.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/plugin/service/PipePluginExecutableManager.java
index 42b559f30d5..fade4351569 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/plugin/service/PipePluginExecutableManager.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/plugin/service/PipePluginExecutableManager.java
@@ -36,6 +36,7 @@ import java.nio.ByteBuffer;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Locale;
 
 public class PipePluginExecutableManager extends ExecutableManager {
 
@@ -46,7 +47,7 @@ public class PipePluginExecutableManager extends 
ExecutableManager {
   }
 
   public boolean isLocalJarMatched(PipePluginMeta pipePluginMeta) throws 
PipeException {
-    final String pluginName = pipePluginMeta.getPluginName();
+    final String pluginName = 
FileUtils.validatePathSegment(pipePluginMeta.getPluginName());
     final String md5FilePath = pluginName + ".txt";
 
     if (hasFileUnderTemporaryRoot(md5FilePath)) {
@@ -94,40 +95,33 @@ public class PipePluginExecutableManager extends 
ExecutableManager {
   }
 
   public boolean hasPluginFileUnderInstallDir(String pluginName, String 
fileName) {
-    return Files.exists(Paths.get(getPluginInstallPathV2(pluginName, 
fileName)));
+    return Files.exists(getPluginInstallPathV2Path(pluginName, fileName));
   }
 
   public String getPluginsDirPath(String pluginName) {
-    return this.libRoot + File.separator + INSTALL_DIR + File.separator + 
pluginName.toUpperCase();
+    return getPluginDirectoryPath(pluginName).toString();
   }
 
   public void removePluginFileUnderLibRoot(String pluginName, String fileName) 
throws IOException {
-    String pluginPath = getPluginInstallPathV2(pluginName, fileName);
-    Path path = Paths.get(pluginPath);
+    final Path path = getPluginInstallPathV2Path(pluginName, fileName);
     Files.deleteIfExists(path);
     Files.deleteIfExists(path.getParent());
   }
 
   public String getPluginInstallPathV2(String pluginName, String fileName) {
-    return this.libRoot
-        + File.separator
-        + INSTALL_DIR
-        + File.separator
-        + pluginName.toUpperCase()
-        + File.separator
-        + fileName;
+    return getPluginInstallPathV2Path(pluginName, fileName).toString();
   }
 
   public String getPluginInstallPathV1(String fileName) {
-    return this.libRoot + File.separator + INSTALL_DIR + File.separator + 
fileName;
+    return resolvePathUnderDirectory(getInstallDirectoryPath(), 
fileName).toString();
   }
 
   public void linkExistedPlugin(
       final String oldPluginName, final String newPluginName, final String 
fileName)
       throws IOException {
     FileUtils.createHardLink(
-        new File(getPluginsDirPath(oldPluginName), fileName),
-        new File(getPluginsDirPath(newPluginName), fileName));
+        getPluginInstallPathV2Path(oldPluginName, fileName).toFile(),
+        getPluginInstallPathV2Path(newPluginName, fileName).toFile());
   }
 
   /**
@@ -138,7 +132,39 @@ public class PipePluginExecutableManager extends 
ExecutableManager {
    */
   public void savePluginToInstallDir(ByteBuffer byteBuffer, String pluginName, 
String fileName)
       throws IOException {
-    String destination = getPluginInstallPathV2(pluginName, fileName);
-    saveToDir(byteBuffer, destination);
+    saveToDir(byteBuffer, getPluginInstallPathV2Path(pluginName, 
fileName).toString());
+  }
+
+  private Path getPluginInstallPathV2Path(final String pluginName, final 
String fileName) {
+    return resolvePathUnderDirectory(getPluginDirectoryPath(pluginName), 
fileName);
+  }
+
+  private Path getPluginDirectoryPath(final String pluginName) {
+    final String validatedPluginName = 
FileUtils.validatePathSegment(pluginName);
+    return resolvePathUnderDirectory(
+        getInstallDirectoryPath(), 
validatedPluginName.toUpperCase(Locale.ROOT));
+  }
+
+  private Path getInstallDirectoryPath() {
+    return Paths.get(libRoot, INSTALL_DIR).toAbsolutePath().normalize();
+  }
+
+  /**
+   * Resolves a single untrusted path segment below {@code baseDirectory}.
+   *
+   * <p>The segment validation rejects separators and dot segments, while the 
normalized containment
+   * check remains as a defense in depth for absolute paths and future callers.
+   */
+  private Path resolvePathUnderDirectory(final Path baseDirectory, final 
String pathSegment) {
+    FileUtils.validatePathSegment(pathSegment);
+
+    final Path normalizedBaseDirectory = 
baseDirectory.toAbsolutePath().normalize();
+    final Path normalizedTargetPath =
+        
normalizedBaseDirectory.resolve(pathSegment).toAbsolutePath().normalize();
+    if (!normalizedTargetPath.startsWith(normalizedBaseDirectory)) {
+      throw new IllegalArgumentException(
+          String.format(PipeMessages.ILLEGAL_FILENAME_PATH_TRAVERSAL, 
pathSegment));
+    }
+    return normalizedTargetPath;
   }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
index a0611a8cfc6..d5b1b76a7eb 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
@@ -42,6 +42,7 @@ import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
 import java.nio.file.StandardOpenOption;
 import java.text.CharacterIterator;
@@ -659,4 +660,19 @@ public class FileUtils {
     }
     return null;
   }
+
+  /**
+   * Validates a path segment before it is used to construct a path.
+   *
+   * <p>In addition to the application-level checks above, constructing a 
{@link Path} validates
+   * platform-specific path syntax (for example, NUL characters on Unix).
+   */
+  public static String validatePathSegment(final String pathSegment) {
+    final String pathError = getIllegalError4Directory(pathSegment);
+    if (pathError != null) {
+      throw new IllegalArgumentException(pathError);
+    }
+    Paths.get(pathSegment);
+    return pathSegment;
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/pipe/agent/plugin/service/PipePluginExecutableManagerTest.java
 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/pipe/agent/plugin/service/PipePluginExecutableManagerTest.java
new file mode 100644
index 00000000000..129c850d99e
--- /dev/null
+++ 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/pipe/agent/plugin/service/PipePluginExecutableManagerTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.commons.pipe.agent.plugin.service;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Comparator;
+import java.util.stream.Stream;
+
+public class PipePluginExecutableManagerTest {
+
+  @Test
+  public void testPluginPathsAreConfinedToInstallDirectory() throws Exception {
+    final Path root = 
Files.createTempDirectory("pipe-plugin-executable-manager-test");
+    final Path temporaryLibRoot = root.resolve("temporary");
+    final Path libRoot = root.resolve("lib");
+    final PipePluginExecutableManager manager =
+        new PipePluginExecutableManager(temporaryLibRoot.toString(), 
libRoot.toString());
+    final String traversalFileName = ".." + File.separator + ".." + 
File.separator + "outside.jar";
+    final Path outsideFile = libRoot.resolve("outside.jar");
+    final byte[] pluginContent = "plugin".getBytes(StandardCharsets.UTF_8);
+
+    try {
+      Assert.assertEquals(
+          libRoot
+              .toAbsolutePath()
+              .normalize()
+              .resolve("install")
+              .resolve("TEST-PLUGIN")
+              .resolve("test.jar"),
+          Path.of(manager.getPluginInstallPathV2("test-plugin", "test.jar")));
+      manager.savePluginToInstallDir(ByteBuffer.wrap(pluginContent), 
"test-plugin", "test.jar");
+      Assert.assertArrayEquals(
+          pluginContent,
+          
Files.readAllBytes(Path.of(manager.getPluginInstallPathV2("test-plugin", 
"test.jar"))));
+
+      Assert.assertThrows(
+          IllegalArgumentException.class,
+          () -> manager.getPluginsDirPath(".." + File.separator + "outside"));
+      Assert.assertThrows(
+          IllegalArgumentException.class,
+          () -> manager.getPluginsDirPath(".." + otherFileSeparator() + 
"outside"));
+      Assert.assertThrows(
+          IllegalArgumentException.class, () -> 
manager.getPluginInstallPathV1(traversalFileName));
+      Assert.assertThrows(
+          IllegalArgumentException.class,
+          () ->
+              manager.savePluginToInstallDir(
+                  ByteBuffer.wrap(new byte[] {1}), "plugin", 
traversalFileName));
+      Assert.assertThrows(
+          IllegalArgumentException.class,
+          () ->
+              manager.savePluginToInstallDir(
+                  ByteBuffer.wrap(new byte[] {1}),
+                  ".." + otherFileSeparator() + "plugin",
+                  "test.jar"));
+      Assert.assertFalse(Files.exists(outsideFile));
+
+      Files.createDirectories(outsideFile.getParent());
+      Files.write(outsideFile, "preserve".getBytes(StandardCharsets.UTF_8));
+      Assert.assertThrows(
+          IllegalArgumentException.class,
+          () -> manager.removePluginFileUnderLibRoot("plugin", 
traversalFileName));
+      Assert.assertArrayEquals(
+          "preserve".getBytes(StandardCharsets.UTF_8), 
Files.readAllBytes(outsideFile));
+
+      Assert.assertThrows(
+          IllegalArgumentException.class,
+          () -> manager.linkExistedPlugin("source", "target", 
traversalFileName));
+    } finally {
+      deleteRecursively(root);
+    }
+  }
+
+  private static String otherFileSeparator() {
+    return File.separatorChar == '/' ? "\\" : "/";
+  }
+
+  private static void deleteRecursively(final Path path) throws IOException {
+    try (final Stream<Path> stream = Files.walk(path)) {
+      for (final Path subPath :
+          (Iterable<Path>) stream.sorted(Comparator.reverseOrder())::iterator) 
{
+        Files.deleteIfExists(subPath);
+      }
+    }
+  }
+}
diff --git 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/pipe/plugin/meta/PipePluginMetaTest.java
 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/pipe/plugin/meta/PipePluginMetaTest.java
index b5b854adc4d..4aa8c5739a9 100644
--- 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/pipe/plugin/meta/PipePluginMetaTest.java
+++ 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/pipe/plugin/meta/PipePluginMetaTest.java
@@ -22,6 +22,7 @@ package org.apache.iotdb.commons.pipe.plugin.meta;
 import org.apache.iotdb.commons.pipe.agent.plugin.builtin.BuiltinPipePlugin;
 import 
org.apache.iotdb.commons.pipe.agent.plugin.meta.ConfigNodePipePluginMetaKeeper;
 import 
org.apache.iotdb.commons.pipe.agent.plugin.meta.DataNodePipePluginMetaKeeper;
+import org.apache.iotdb.commons.pipe.agent.plugin.meta.PipePluginMeta;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -58,4 +59,20 @@ public class PipePluginMetaTest {
         BuiltinPipePlugin.IOTDB_EXTRACTOR.getPipePluginClass(),
         
keeper.getBuiltinPluginClass(BuiltinPipePlugin.IOTDB_EXTRACTOR.getPipePluginName()));
   }
+
+  @Test
+  public void testRejectPathTraversalInPluginMetadata() {
+    Assert.assertThrows(
+        IllegalArgumentException.class,
+        () -> new PipePluginMeta("../plugin", "test.Plugin", false, 
"test.jar", "md5"));
+    Assert.assertThrows(
+        IllegalArgumentException.class,
+        () -> new PipePluginMeta("plugin", "test.Plugin", false, 
"../test.jar", "md5"));
+    Assert.assertThrows(
+        IllegalArgumentException.class,
+        () -> new PipePluginMeta("plugin", "test.Plugin", false, 
"..\\test.jar", "md5"));
+    Assert.assertThrows(
+        IllegalArgumentException.class,
+        () -> new PipePluginMeta("plugin\0", "test.Plugin", false, "test.jar", 
"md5"));
+  }
 }

Reply via email to