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

reta pushed a commit to branch 4.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit eda8a54dc40102a2b869440ed769eda252fa38ef
Author: Andriy Redko <[email protected]>
AuthorDate: Tue Jun 2 11:36:41 2026 -0400

    Add limit to the maximum number of attachment headers to be collected 
(#3159)
    
    (cherry picked from commit cc0ef249b7cba0be484c62b17445372d31fcea10)
---
 .../attachment/AttachmentBoundaryDeserializer.java |  8 +++++++-
 .../cxf/attachment/AttachmentDeserializer.java     | 17 ++++++++++++++--
 .../cxf/attachment/AttachmentDeserializerUtil.java | 14 +++++++++----
 .../cxf/attachment/AttachmentDeserializerTest.java | 23 ++++++++++++++++++++++
 4 files changed, 55 insertions(+), 7 deletions(-)

diff --git 
a/core/src/main/java/org/apache/cxf/attachment/AttachmentBoundaryDeserializer.java
 
b/core/src/main/java/org/apache/cxf/attachment/AttachmentBoundaryDeserializer.java
index 72675a0e5cd..e7bdc7d616d 100644
--- 
a/core/src/main/java/org/apache/cxf/attachment/AttachmentBoundaryDeserializer.java
+++ 
b/core/src/main/java/org/apache/cxf/attachment/AttachmentBoundaryDeserializer.java
@@ -38,12 +38,17 @@ public class AttachmentBoundaryDeserializer {
     private static final int PUSHBACK_AMOUNT = 2048;
     
     private final int maxHeaderLength;
+    private final int maxHeadersCount;
     private final Message message;
 
     public AttachmentBoundaryDeserializer(Message message) {
         this.message = message;
         this.maxHeaderLength = MessageUtils.getContextualInteger(message, 
             AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE, 
AttachmentDeserializer.DEFAULT_MAX_HEADER_SIZE);
+        // Get the maximum headers count
+        this.maxHeadersCount = MessageUtils.getContextualInteger(message,
+            AttachmentDeserializer.ATTACHMENT_HEADERS_MAX_COUNT, 
+                AttachmentDeserializer.DEFAULT_ATTACHMENT_HEADERS_MAX_COUNT);
     }
 
     public Attachment read(InputStream body) throws IOException {
@@ -60,7 +65,8 @@ public class AttachmentBoundaryDeserializer {
             throw new IOException("Couldn't find MIME boundary: " + 
boundaryString);
         }
 
-        Map<String, List<String>> ih = 
AttachmentDeserializerUtil.loadPartHeaders(stream, maxHeaderLength);
+        final Map<String, List<String>> ih = AttachmentDeserializerUtil
+            .loadPartHeaders(stream, maxHeaderLength, maxHeadersCount);
         String val = AttachmentUtil.getHeader(ih, "Content-Transfer-Encoding");
 
         MimeBodyPartInputStream mmps = new MimeBodyPartInputStream(stream, 
boundary, PUSHBACK_AMOUNT);
diff --git 
a/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java 
b/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java
index d3b87411eac..d5c6409cb56 100644
--- a/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java
+++ b/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java
@@ -67,6 +67,13 @@ public class AttachmentDeserializer {
      */
     public static final String ATTACHMENT_MAX_COUNT = "attachment-max-count";
 
+    /**
+     * The maximum number of attachment headers permitted in a message. The 
default is 500.
+     */
+    public static final String ATTACHMENT_HEADERS_MAX_COUNT = 
"attachment-headers-max-count";
+    public static final int DEFAULT_ATTACHMENT_HEADERS_MAX_COUNT =
+        
SystemPropertyAction.getInteger("org.apache.cxf.attachment-max-headers-count", 
500);
+
     /**
      * The maximum MIME Header Length. The default is 300.
      */
@@ -102,6 +109,7 @@ public class AttachmentDeserializer {
     private List<String> supportedTypes;
 
     private int maxHeaderLength = DEFAULT_MAX_HEADER_SIZE;
+    private int maxHeadersCount = DEFAULT_ATTACHMENT_HEADERS_MAX_COUNT;
 
     public AttachmentDeserializer(Message message) {
         this(message, Collections.singletonList("multipart/related"));
@@ -114,6 +122,9 @@ public class AttachmentDeserializer {
         // Get the maximum Header length from configuration
         maxHeaderLength = MessageUtils.getContextualInteger(message, 
ATTACHMENT_MAX_HEADER_SIZE,
                                                             
DEFAULT_MAX_HEADER_SIZE);
+        // Get the maximum headers count
+        maxHeadersCount = MessageUtils.getContextualInteger(message, 
ATTACHMENT_HEADERS_MAX_COUNT,
+                                                            
DEFAULT_ATTACHMENT_HEADERS_MAX_COUNT);
     }
 
     public void initializeAttachments() throws IOException {
@@ -160,7 +171,8 @@ public class AttachmentDeserializer {
                 throw new IOException("Couldn't find MIME boundary: " + 
boundaryString);
             }
 
-            Map<String, List<String>> ih = 
AttachmentDeserializerUtil.loadPartHeaders(stream, maxHeaderLength);
+            final Map<String, List<String>> ih = AttachmentDeserializerUtil
+                .loadPartHeaders(stream, maxHeaderLength, maxHeadersCount);
             message.put(ATTACHMENT_PART_HEADERS, ih);
             String val = AttachmentUtil.getHeader(ih, "Content-Type", "; ");
             if (!StringUtils.isEmpty(val)) {
@@ -225,7 +237,8 @@ public class AttachmentDeserializer {
         }
         stream.unread(v);
 
-        Map<String, List<String>> headers = 
AttachmentDeserializerUtil.loadPartHeaders(stream, maxHeaderLength);
+        final Map<String, List<String>> headers = AttachmentDeserializerUtil
+            .loadPartHeaders(stream, maxHeaderLength, maxHeadersCount);
         return (AttachmentImpl)createAttachment(headers);
     }
 
diff --git 
a/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializerUtil.java 
b/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializerUtil.java
index 98ee9a468c2..c74d70c2962 100644
--- 
a/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializerUtil.java
+++ 
b/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializerUtil.java
@@ -80,7 +80,8 @@ final class AttachmentDeserializerUtil {
     }
 
 
-    static Map<String, List<String>> loadPartHeaders(InputStream in, int 
maxHeaderLength) throws IOException {
+    static Map<String, List<String>> loadPartHeaders(InputStream in, int 
maxHeaderLength, 
+            int maxHeadersCount) throws IOException {
         StringBuilder buffer = new StringBuilder(128);
         StringBuilder b = new StringBuilder(128);
         Map<String, List<String>> heads = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
@@ -98,7 +99,7 @@ final class AttachmentDeserializerUtil {
             } else {
                 // if we have a line pending in the buffer, flush it
                 if (buffer.length() > 0) {
-                    addHeaderLine(heads, buffer);
+                    addHeaderLine(heads, buffer, maxHeadersCount);
                     buffer.setLength(0);
                 }
                 // add this to the accumulator
@@ -108,7 +109,7 @@ final class AttachmentDeserializerUtil {
 
         // if we have a line pending in the buffer, flush it
         if (buffer.length() > 0) {
-            addHeaderLine(heads, buffer);
+            addHeaderLine(heads, buffer, maxHeadersCount);
         }
         return heads;
     }
@@ -142,7 +143,8 @@ final class AttachmentDeserializerUtil {
         return buffer.length() != 0;
     }
 
-    private static void addHeaderLine(Map<String, List<String>> heads, 
StringBuilder line) {
+    private static void addHeaderLine(Map<String, List<String>> heads, 
StringBuilder line, 
+            int maxHeadersCount) throws IOException {
         // null lines are a nop
         final int size = line.length();
         if (size == 0) {
@@ -167,6 +169,10 @@ final class AttachmentDeserializerUtil {
             }
             value = line.substring(separator);
         }
+        
+        if (heads.size() >= maxHeadersCount) {
+            throw new IOException("The attachment contains more headers than 
are permitted");
+        }
         List<String> v = heads.computeIfAbsent(name, k -> new ArrayList<>(1));
         v.add(value);
     }
diff --git 
a/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java 
b/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java
index 70657184808..eec76dbba9c 100644
--- 
a/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java
+++ 
b/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java
@@ -20,6 +20,7 @@ package org.apache.cxf.attachment;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.PushbackInputStream;
 import java.nio.charset.StandardCharsets;
@@ -667,6 +668,28 @@ public class AttachmentDeserializerTest {
         ins.close();
     }
 
+    @Test
+    public void testManyAttachmentHeaders() throws Exception {
+        StringBuilder sb = new StringBuilder(10000);
+        // Add many attachment headers
+        sb.append("------=_Part_34950_1098328613.1263781527359\n");
+        IntStream.range(0, 1000).forEach(i -> 
sb.append("Header-").append(i).append(": foo").append(i).append('\n'));
+        sb.append("Content-Type: text/xml; charset=UTF-8\n")
+            .append("Content-Transfer-Encoding: binary\n")
+            .append("Content-Id: 
<318731183421.1263781527359.IBM.WEBSERVICES@auhpap02>\n")
+            .append('\n')
+            .append("<envelope/>\n");
+
+        msg = new MessageImpl();
+        msg.setContent(InputStream.class, new 
ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8)));
+        msg.put(Message.CONTENT_TYPE, "multipart/related");
+        AttachmentDeserializer ad = new AttachmentDeserializer(msg);
+
+        assertThrows("Failure expected on too many attachment headers", 
IOException.class, 
+            () -> ad.initializeAttachments());
+    }
+
+    
     @Test
     public void testManyAttachments() throws Exception {
         StringBuilder sb = new StringBuilder(1000);

Reply via email to