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

JackieTien97 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 8940ba0e3f5 fix(jdbc): prevent BigDecimal DoS in 
StringUtils.consistentToString (#17508)
8940ba0e3f5 is described below

commit 8940ba0e3f5b199af170193128395ec2c5e262fa
Author: Le Yang <[email protected]>
AuthorDate: Mon Jul 6 12:22:48 2026 +0800

    fix(jdbc): prevent BigDecimal DoS in StringUtils.consistentToString (#17508)
---
 .../java/org/apache/iotdb/jdbc/StringUtils.java    | 21 +++++-
 .../org/apache/iotdb/jdbc/StringUtilsTest.java     | 74 ++++++++++++++++++++++
 2 files changed, 94 insertions(+), 1 deletion(-)

diff --git 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/StringUtils.java 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/StringUtils.java
index a7bdaab0e67..845190a013c 100644
--- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/StringUtils.java
+++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/StringUtils.java
@@ -44,6 +44,18 @@ public class StringUtils {
 
   static final int WILD_COMPARE_NO_MATCH = -1;
 
+  /**
+   * Maximum absolute {@link BigDecimal#scale()} accepted by {@link 
#consistentToString(BigDecimal)}
+   * before it falls back to scientific notation.
+   *
+   * <p>{@link BigDecimal#toPlainString()} expands the value to a 
non-scientific decimal string
+   * whose length grows with {@code |scale|}. A value such as {@code 
1e1000000000} would therefore
+   * materialize a ~1GB {@link String}, causing {@link OutOfMemoryError} / 
denial of service on the
+   * client. Any scale beyond this bound is rejected for expansion and the 
caller gets the
+   * scientific form instead, which is a few dozen characters at most.
+   */
+  static final int MAX_PLAIN_STRING_SCALE = 10_000;
+
   static {
     for (int i = -128; i <= 127; i++) {
       allBytes[i - -128] = (byte) i;
@@ -65,9 +77,16 @@ public class StringUtils {
     if (decimal == null) {
       return null;
     }
+    // Guard against CVE-style DoS: BigDecimal values constructed from extreme 
scientific
+    // notation (e.g. "1e1000000000") have a huge |scale| and would otherwise 
cause
+    // toPlainString() to allocate a multi-GB String and OOM the JVM. Fall 
back to the
+    // scientific form, which is always short.
+    if (decimal.scale() > MAX_PLAIN_STRING_SCALE || decimal.scale() < 
-MAX_PLAIN_STRING_SCALE) {
+      return decimal.toString();
+    }
     if (toPlainStringMethod != null) {
       try {
-        return (String) toPlainStringMethod.invoke(decimal, null);
+        return (String) toPlainStringMethod.invoke(decimal, (Object[]) null);
       } catch (InvocationTargetException | IllegalAccessException e) {
         LOGGER.warn(JdbcMessages.CONSISTENT_TO_STRING_ERROR, e);
       }
diff --git 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/StringUtilsTest.java 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/StringUtilsTest.java
new file mode 100644
index 00000000000..906eeef8e08
--- /dev/null
+++ b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/StringUtilsTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.jdbc;
+
+import org.junit.Test;
+
+import java.math.BigDecimal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class StringUtilsTest {
+
+  @Test
+  public void consistentToStringHandlesNull() {
+    assertNull(StringUtils.consistentToString(null));
+  }
+
+  @Test
+  public void consistentToStringExpandsNormalDecimal() {
+    assertEquals("123.45", StringUtils.consistentToString(new 
BigDecimal("123.45")));
+    // Plain-string form, not scientific notation.
+    assertEquals("100", StringUtils.consistentToString(new 
BigDecimal("1E+2")));
+  }
+
+  @Test
+  public void consistentToStringExpandsUpToLimit() {
+    // scale right at the boundary must still be expanded to plain form.
+    BigDecimal atLimit = new BigDecimal("1E+" + 
StringUtils.MAX_PLAIN_STRING_SCALE);
+    String out = StringUtils.consistentToString(atLimit);
+    assertEquals(StringUtils.MAX_PLAIN_STRING_SCALE + 1, out.length());
+    assertTrue(out.startsWith("1"));
+  }
+
+  /**
+   * Regression test for the BigDecimal DoS: {@code new 
BigDecimal("1e1000000000")} used to cause
+   * {@link BigDecimal#toPlainString()} to allocate a ~1GB string and OOM the 
JVM. The guard must
+   * refuse to expand such values and return the compact scientific form 
instead.
+   */
+  @Test
+  public void consistentToStringRefusesToExpandHugeScale() {
+    BigDecimal malicious = new BigDecimal("1e1000000000");
+    String out = StringUtils.consistentToString(malicious);
+    // Must be short (scientific notation), never the ~1e9-char plain form.
+    assertTrue("expected scientific form, got length " + out.length(), 
out.length() < 64);
+    assertTrue(out.contains("E") || out.contains("e"));
+  }
+
+  @Test
+  public void consistentToStringRefusesToExpandHugePositiveScale() {
+    // Very large positive scale -> also produces a long plain string; must be 
refused.
+    BigDecimal malicious = new BigDecimal("1e-1000000000");
+    String out = StringUtils.consistentToString(malicious);
+    assertTrue("expected scientific form, got length " + out.length(), 
out.length() < 64);
+  }
+}

Reply via email to