VYPR
Medium severity5.5NVD Advisory· Published Nov 14, 2017· Updated May 13, 2026

CVE-2017-12624

CVE-2017-12624

Description

Apache CXF supports sending and receiving attachments via either the JAX-WS or JAX-RS specifications. It is possible to craft a message attachment header that could lead to a Denial of Service (DoS) attack on a CXF web service provider. Both JAX-WS and JAX-RS services are vulnerable to this attack. From Apache CXF 3.2.1 and 3.1.14, message attachment headers that are greater than 300 characters will be rejected by default. This value is configurable via the property "attachment-max-header-size".

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Apache CXF 3.2.x before 3.2.1 and 3.1.x before 3.1.14 are vulnerable to a denial-of-service attack via crafted message attachment headers.

Vulnerability

Apache CXF, a Java framework for building web services, is vulnerable to a denial-of-service (DoS) attack when processing message attachments via JAX-WS or JAX-RS specifications. An attacker can craft a message attachment header with an oversized value, causing excessive resource consumption. Versions prior to 3.2.1 and 3.1.14 are affected. The fix introduced a default maximum header size of 300 characters, configurable via the property attachment-max-header-size [1][3].

Exploitation

An attacker can send a SOAP or REST message containing an attachment with a header field exceeding the previous unlimited size. No authentication or special network position is required; the attacker only needs to submit a malicious request to a CXF endpoint processing attachments [1][3].

Impact

Successful exploitation leads to denial of service, as the CXF service may hang or crash while parsing the oversized header, disrupting availability for legitimate users [1][3].

Mitigation

Upgrade to Apache CXF 3.2.1 or 3.1.14 (released November 2017), which reject attachment headers larger than 300 characters by default. Administrators can also lower the attachment-max-header-size property. Red Hat products affected, such as Red Hat JBoss Enterprise Application Platform, received fixes via RHSA-2018:2423 and RHSA-2018:2424 [1][2][3].

AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.apache.cxf:cxf-coreMaven
>= 3.2.0, < 3.2.13.2.1
org.apache.cxf:cxf-coreMaven
>= 3.1.0, < 3.1.143.1.14
org.apache.cxf:cxf-coreMaven
< 3.0.163.0.16

Affected products

2

Patches

3
a2ce435cf0ee

CXF-7507 - Put a configurable limit on the size of attachment headers

https://github.com/apache/cxfColm O hEigeartaighOct 3, 2017via ghsa
8 files changed · +169 6
  • core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java+24 0 modified
    @@ -29,17 +29,20 @@
     import java.util.Map;
     import java.util.Set;
     import java.util.TreeMap;
    +import java.util.logging.Logger;
     import java.util.regex.Matcher;
     import java.util.regex.Pattern;
     
     import javax.activation.DataSource;
     
    +import org.apache.cxf.common.logging.LogUtils;
     import org.apache.cxf.common.util.StringUtils;
     import org.apache.cxf.helpers.HttpHeaderHelper;
     import org.apache.cxf.helpers.IOUtils;
     import org.apache.cxf.io.CachedOutputStream;
     import org.apache.cxf.message.Attachment;
     import org.apache.cxf.message.Message;
    +import org.apache.cxf.message.MessageUtils;
     
     public class AttachmentDeserializer {
         public static final String ATTACHMENT_PART_HEADERS = AttachmentDeserializer.class.getName() + ".headers";
    @@ -49,6 +52,12 @@ public class AttachmentDeserializer {
     
         public static final String ATTACHMENT_MAX_SIZE = "attachment-max-size";
     
    +    /**
    +     * The maximum MIME Header Length. The default is 300.
    +     */
    +    public static final String ATTACHMENT_MAX_HEADER_SIZE = "attachment-max-header-size";
    +    public static final int DEFAULT_MAX_HEADER_SIZE = 300;
    +
         public static final int THRESHOLD = 1024 * 100; //100K (byte unit)
     
         private static final Pattern CONTENT_TYPE_BOUNDARY_PATTERN = Pattern.compile("boundary=\"?([^\";]*)");
    @@ -58,6 +67,8 @@ public class AttachmentDeserializer {
         private static final Pattern INPUT_STREAM_BOUNDARY_PATTERN =
                 Pattern.compile("^--(\\S*)$", Pattern.MULTILINE);
     
    +    private static final Logger LOG = LogUtils.getL7dLogger(AttachmentDeserializer.class);
    +
         private boolean lazyLoading = true;
     
         private int pbAmount = 2048;
    @@ -79,13 +90,19 @@ public class AttachmentDeserializer {
         private Set<DelegatingInputStream> loaded = new HashSet<DelegatingInputStream>();
         private List<String> supportedTypes;
     
    +    private int maxHeaderLength = DEFAULT_MAX_HEADER_SIZE;
    +
         public AttachmentDeserializer(Message message) {
             this(message, Collections.singletonList("multipart/related"));
         }
     
         public AttachmentDeserializer(Message message, List<String> supportedTypes) {
             this.message = message;
             this.supportedTypes = supportedTypes;
    +
    +        // Get the maximum Header length from configuration
    +        maxHeaderLength = MessageUtils.getContextualInteger(message, ATTACHMENT_MAX_HEADER_SIZE,
    +                                                            DEFAULT_MAX_HEADER_SIZE);
         }
         
         public void initializeAttachments() throws IOException {
    @@ -286,6 +303,7 @@ private Attachment createAttachment(Map<String, List<String>> headers) throws IO
                 new DelegatingInputStream(new MimeBodyPartInputStream(stream, boundary, pbAmount),
                                           this);
             createCount++;
    +
             return AttachmentUtil.createAttachment(partStream, headers);
         }
     
    @@ -334,6 +352,7 @@ private Map<String, List<String>> loadPartHeaders(InputStream in) throws IOExcep
             List<String> headerLines = new ArrayList<String>(10);
             StringBuilder buffer = new StringBuilder(128);
             String line;
    +
             // loop until we hit the end or a null line
             while ((line = readLine(in)) != null) {
                 // lines beginning with white space get special handling
    @@ -412,6 +431,11 @@ private String readLine(InputStream in) throws IOException {
                     // just add to the buffer
                     buffer.append((char)c);
                 }
    +
    +            if (buffer.length() > maxHeaderLength) {
    +                LOG.fine("The attachment header size has exceeded the configured parameter: " + maxHeaderLength);
    +                throw new HeaderSizeExceededException();
    +            }
             }
     
             // no characters found...this was either an eof or a null line.
    
  • core/src/main/java/org/apache/cxf/attachment/ContentDisposition.java+1 1 modified
    @@ -28,7 +28,7 @@
     
     public class ContentDisposition {
         private static final String CD_HEADER_PARAMS_EXPRESSION =
    -        "(([\\w-]+( )?\\*?=( )?\"[^\"]+\")|([\\w-]+( )?\\*?=( )?[^;]+))";
    +       "[\\w-]++( )?\\*?=( )?((\"[^\"]++\")|([^;]+))";
         private static final Pattern CD_HEADER_PARAMS_PATTERN =
                 Pattern.compile(CD_HEADER_PARAMS_EXPRESSION);
     
    
  • core/src/main/java/org/apache/cxf/attachment/HeaderSizeExceededException.java+40 0 added
    @@ -0,0 +1,40 @@
    +/**
    + * 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.cxf.attachment;
    +
    +public class HeaderSizeExceededException extends RuntimeException {
    +    private static final long serialVersionUID = -8976580055837650080L;
    +
    +    public HeaderSizeExceededException() {
    +        super();
    +    }
    +
    +    public HeaderSizeExceededException(String message) {
    +        super(message);
    +    }
    +
    +    public HeaderSizeExceededException(String message, Throwable cause) {
    +        super(message, cause);
    +    }
    +
    +    public HeaderSizeExceededException(Throwable cause) {
    +        super(cause);
    +    }
    +}
    
  • core/src/main/java/org/apache/cxf/message/MessageUtils.java+23 1 modified
    @@ -19,8 +19,11 @@
     
     package org.apache.cxf.message;
     
    +import java.util.logging.Logger;
    +
     import org.w3c.dom.Node;
     
    +import org.apache.cxf.common.logging.LogUtils;
     import org.apache.cxf.common.util.PropertyUtils;
     
     
    @@ -29,6 +32,8 @@
      */
     public final class MessageUtils {
     
    +    private static final Logger LOG = LogUtils.getL7dLogger(MessageUtils.class);
    +
         /**
          * Prevents instantiation.
          */
    @@ -139,7 +144,24 @@ public static boolean getContextualBoolean(Message m, String key, boolean defaul
             }
             return defaultValue;
         }
    -    
    +
    +    public static int getContextualInteger(Message m, String key, int defaultValue) {
    +        if (m != null) {
    +            Object o = m.getContextualProperty(key);
    +            if (o instanceof String) {
    +                try {
    +                    int i = Integer.parseInt((String)o);
    +                    if (i > 0) {
    +                        return i;
    +                    }
    +                } catch (NumberFormatException ex) {
    +                    LOG.warning("Incorrect integer value of " + o + " specified for: " + key);
    +                }
    +            }
    +        }
    +        return defaultValue;
    +    }
    +
         public static Object getContextualProperty(Message m, String propPreferred, String propDefault) {
             Object prop = null;
             if (m != null) {
    
  • rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/MessageContextImpl.java+8 1 modified
    @@ -45,6 +45,7 @@
     import org.apache.cxf.attachment.AttachmentDeserializer;
     import org.apache.cxf.attachment.AttachmentImpl;
     import org.apache.cxf.attachment.AttachmentUtil;
    +import org.apache.cxf.attachment.HeaderSizeExceededException;
     import org.apache.cxf.endpoint.Endpoint;
     import org.apache.cxf.helpers.CastUtils;
     import org.apache.cxf.interceptor.AttachmentOutInterceptor;
    @@ -64,6 +65,7 @@
     import org.apache.cxf.message.MessageUtils;
     
     public class MessageContextImpl implements MessageContext {
    +
         private Message m;
         public MessageContextImpl(Message m) {
             this.m = m;
    @@ -78,6 +80,8 @@ public Object get(Object key) {
                 } catch (CacheSizeExceededException e) {
                     m.getExchange().put("cxf.io.cacheinput", Boolean.FALSE);
                     throw new WebApplicationException(e, 413);
    +            } catch (HeaderSizeExceededException e) {
    +                throw new WebApplicationException(e, 413);
                 }
             }
             if (keyValue.equals("WRITE-" + Message.ATTACHMENTS)) {
    @@ -269,7 +273,9 @@ private MultipartBody createAttachments(String propertyName) {
                     m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MEMORY_THRESHOLD));
                 inMessage.put(AttachmentDeserializer.ATTACHMENT_MAX_SIZE,
                     m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MAX_SIZE));
    -            inMessage.setContent(InputStream.class, 
    +            inMessage.put(AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE,
    +                m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE));
    +            inMessage.setContent(InputStream.class,
                     m.getExchange().getInMessage().get("org.apache.cxf.multipart.embedded.input"));
                 inMessage.put(Message.CONTENT_TYPE, 
                     m.getExchange().getInMessage().get("org.apache.cxf.multipart.embedded.ctype").toString());
    @@ -282,6 +288,7 @@ private MultipartBody createAttachments(String propertyName) {
             try {
                 Map<String, List<String>> headers 
                     = CastUtils.cast((Map<?, ?>)inMessage.get(AttachmentDeserializer.ATTACHMENT_PART_HEADERS));
    +
                 Attachment first = new Attachment(AttachmentUtil.createAttachment(
                                          inMessage.getContent(InputStream.class), 
                                          headers),
    
  • rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/multipart/Attachment.java+8 3 modified
    @@ -88,7 +88,7 @@ public Attachment(InputStream is, MultivaluedMap<String, String> headers) {
                  new DataHandler(new InputStreamDataSource(is, headers.getFirst("Content-Type"))), 
                  headers);
         }
    -    
    +
         public Attachment(String id, String mediaType, Object object) {
             this.object = object;
             headers.putSingle("Content-ID", id);
    @@ -103,8 +103,8 @@ public Attachment(String id, InputStream is, ContentDisposition cd) {
             headers.putSingle("Content-ID", id);
             headers.putSingle("Content-Type", "application/octet-stream");
         }
    -    
    -    Attachment(MultivaluedMap<String, String> headers, DataHandler handler, Object object) {
    +
    +    public Attachment(MultivaluedMap<String, String> headers, DataHandler handler, Object object) {
             this.headers = headers;
             this.handler = handler;
             this.object = object;
    @@ -121,7 +121,12 @@ public String getContentId() {
         }
     
         public MediaType getContentType() {
    +<<<<<<< HEAD
             String value = handler != null ? handler.getContentType() : headers.getFirst("Content-Type");
    +=======
    +        String value = handler != null && handler.getContentType() != null ? handler.getContentType()
    +            : headers.getFirst("Content-Type");
    +>>>>>>> 896bd961cb... CXF-7507 - Put a configurable limit on the size of attachment headers
             return value == null ? MediaType.TEXT_PLAIN_TYPE : JAXRSUtils.toMediaType(value);
         }
     
    
  • systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java+64 0 modified
    @@ -39,6 +39,7 @@
     import javax.imageio.ImageIO;
     import javax.mail.util.ByteArrayDataSource;
     import javax.ws.rs.core.MediaType;
    +import javax.ws.rs.core.MultivaluedHashMap;
     import javax.ws.rs.core.MultivaluedMap;
     import javax.ws.rs.core.Response;
     import javax.xml.bind.JAXBContext;
    @@ -62,6 +63,7 @@
     import org.apache.cxf.jaxrs.client.WebClient;
     import org.apache.cxf.jaxrs.ext.multipart.Attachment;
     import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition;
    +import org.apache.cxf.jaxrs.ext.multipart.InputStreamDataSource;
     import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
     import org.apache.cxf.jaxrs.impl.MetadataMap;
     import org.apache.cxf.jaxrs.provider.json.JSONProvider;
    @@ -942,6 +944,67 @@ public void testMultipartRequestTooLargeManyParts() throws Exception {
             }
         }
     
    +    // The large Content Disposition header will be rejected here
    +    @Test
    +    public void testLargeHeader() throws Exception {
    +        InputStream is1 =
    +            getClass().getResourceAsStream("/org/apache/cxf/systest/jaxrs/resources/java.jpg");
    +        String address = "http://localhost:" + PORT + "/bookstore/books/image";
    +        WebClient client = WebClient.create(address);
    +        client.type("multipart/mixed").accept("multipart/mixed");
    +        WebClient.getConfig(client).getRequestContext().put("support.type.as.multipart",
    +            "true");
    +
    +        StringBuilder sb = new StringBuilder();
    +        sb.append("form-data;");
    +        for (int i = 0; i < 10000; i++) {
    +            sb.append("aaaaaaaaaa");
    +        }
    +
    +        MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
    +        headers.putSingle("Content-ID", "root");
    +        headers.putSingle("Content-Type", "application/octet-stream");
    +        headers.putSingle("Content-Disposition", sb.toString());
    +        DataHandler handler = new DataHandler(new InputStreamDataSource(is1, "application/octet-stream"));
    +
    +        Attachment att = new Attachment(headers, handler, null);
    +        Response response = client.post(att);
    +        assertEquals(response.getStatus(), 413);
    +
    +        client.close();
    +    }
    +
    +    // The Content Disposition header will be accepted here, even though it is larger than the default,
    +    // as we have configured a larger value on the service side
    +    @Test
    +    public void testLargerThanDefaultHeader() throws Exception {
    +        InputStream is1 =
    +            getClass().getResourceAsStream("/org/apache/cxf/systest/jaxrs/resources/java.jpg");
    +        String address = "http://localhost:" + PORT + "/bookstore/books/image";
    +        WebClient client = WebClient.create(address);
    +        client.type("multipart/mixed").accept("multipart/mixed");
    +        WebClient.getConfig(client).getRequestContext().put("support.type.as.multipart",
    +            "true");
    +
    +        StringBuilder sb = new StringBuilder();
    +        sb.append("form-data;");
    +        for (int i = 0; i < 35; i++) {
    +            sb.append("aaaaaaaaaa");
    +        }
    +
    +        MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
    +        headers.putSingle("Content-ID", "root");
    +        headers.putSingle("Content-Type", "application/octet-stream");
    +        headers.putSingle("Content-Disposition", sb.toString());
    +        DataHandler handler = new DataHandler(new InputStreamDataSource(is1, "application/octet-stream"));
    +
    +        Attachment att = new Attachment(headers, handler, null);
    +        Response response = client.post(att);
    +        assertEquals(response.getStatus(), 200);
    +
    +        client.close();
    +    }
    +
         private void doAddBook(String address, String resourceName, int status) throws Exception {
             doAddBook("multipart/related", address, resourceName, status);
         }
    @@ -1031,4 +1094,5 @@ private String stripXmlInstructionIfNeeded(String str) {
             }
             return str;
         }
    +
     }
    
  • systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartServer.java+1 0 modified
    @@ -40,6 +40,7 @@ protected void run() {
             Map<String, Object> props = new HashMap<String, Object>();
             props.put(AttachmentDeserializer.ATTACHMENT_MAX_SIZE, String.valueOf(1024 * 10));
             props.put(AttachmentDeserializer.ATTACHMENT_MEMORY_THRESHOLD, String.valueOf(1024 * 5));
    +        props.put(AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE, String.valueOf(400));
             sf.setProperties(props);
             //default lifecycle is per-request, change it to singleton
             sf.setResourceProvider(MultipartStore.class,
    
8bd915bfd773

CXF-7507 - Put a configurable limit on the size of attachment headers

https://github.com/apache/cxfColm O hEigeartaighOct 3, 2017via ghsa
8 files changed · +162 4
  • core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java+24 0 modified
    @@ -29,17 +29,20 @@
     import java.util.Map;
     import java.util.Set;
     import java.util.TreeMap;
    +import java.util.logging.Logger;
     import java.util.regex.Matcher;
     import java.util.regex.Pattern;
     
     import javax.activation.DataSource;
     
    +import org.apache.cxf.common.logging.LogUtils;
     import org.apache.cxf.common.util.StringUtils;
     import org.apache.cxf.helpers.HttpHeaderHelper;
     import org.apache.cxf.helpers.IOUtils;
     import org.apache.cxf.io.CachedOutputStream;
     import org.apache.cxf.message.Attachment;
     import org.apache.cxf.message.Message;
    +import org.apache.cxf.message.MessageUtils;
     
     public class AttachmentDeserializer {
         public static final String ATTACHMENT_PART_HEADERS = AttachmentDeserializer.class.getName() + ".headers";
    @@ -49,13 +52,21 @@ public class AttachmentDeserializer {
     
         public static final String ATTACHMENT_MAX_SIZE = "attachment-max-size";
     
    +    /**
    +     * The maximum MIME Header Length. The default is 300.
    +     */
    +    public static final String ATTACHMENT_MAX_HEADER_SIZE = "attachment-max-header-size";
    +    public static final int DEFAULT_MAX_HEADER_SIZE = 300;
    +
         public static final int THRESHOLD = 1024 * 100; //100K (byte unit)
     
         private static final Pattern CONTENT_TYPE_BOUNDARY_PATTERN = Pattern.compile("boundary=\"?([^\";]*)");
     
         private static final Pattern INPUT_STREAM_BOUNDARY_PATTERN =
                 Pattern.compile("^--(\\S*)$", Pattern.MULTILINE);
     
    +    private static final Logger LOG = LogUtils.getL7dLogger(AttachmentDeserializer.class);
    +
         private boolean lazyLoading = true;
     
         private int pbAmount = 2048;
    @@ -77,13 +88,19 @@ public class AttachmentDeserializer {
         private Set<DelegatingInputStream> loaded = new HashSet<>();
         private List<String> supportedTypes;
     
    +    private int maxHeaderLength = DEFAULT_MAX_HEADER_SIZE;
    +
         public AttachmentDeserializer(Message message) {
             this(message, Collections.singletonList("multipart/related"));
         }
     
         public AttachmentDeserializer(Message message, List<String> supportedTypes) {
             this.message = message;
             this.supportedTypes = supportedTypes;
    +
    +        // Get the maximum Header length from configuration
    +        maxHeaderLength = MessageUtils.getContextualInteger(message, ATTACHMENT_MAX_HEADER_SIZE,
    +                                                            DEFAULT_MAX_HEADER_SIZE);
         }
     
         public void initializeAttachments() throws IOException {
    @@ -277,6 +294,7 @@ private Attachment createAttachment(Map<String, List<String>> headers) throws IO
                 new DelegatingInputStream(new MimeBodyPartInputStream(stream, boundary, pbAmount),
                                           this);
             createCount++;
    +
             return AttachmentUtil.createAttachment(partStream, headers);
         }
     
    @@ -325,6 +343,7 @@ private Map<String, List<String>> loadPartHeaders(InputStream in) throws IOExcep
             StringBuilder buffer = new StringBuilder(128);
             StringBuilder b = new StringBuilder(128);
             Map<String, List<String>> heads = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER);
    +
             // loop until we hit the end or a null line
             while (readLine(in, b)) {
                 // lines beginning with white space get special handling
    @@ -371,6 +390,11 @@ private boolean readLine(InputStream in, StringBuilder buffer) throws IOExceptio
                     // just add to the buffer
                     buffer.append((char)c);
                 }
    +
    +            if (buffer.length() > maxHeaderLength) {
    +                LOG.fine("The attachment header size has exceeded the configured parameter: " + maxHeaderLength);
    +                throw new HeaderSizeExceededException();
    +            }
             }
     
             // no characters found...this was either an eof or a null line.
    
  • core/src/main/java/org/apache/cxf/attachment/ContentDisposition.java+1 1 modified
    @@ -28,7 +28,7 @@
     
     public class ContentDisposition {
         private static final String CD_HEADER_PARAMS_EXPRESSION =
    -        "(([\\w-]+( )?\\*?=( )?\"[^\"]+\")|([\\w-]+( )?\\*?=( )?[^;]+))";
    +       "[\\w-]++( )?\\*?=( )?((\"[^\"]++\")|([^;]+))";
         private static final Pattern CD_HEADER_PARAMS_PATTERN =
                 Pattern.compile(CD_HEADER_PARAMS_EXPRESSION);
     
    
  • core/src/main/java/org/apache/cxf/attachment/HeaderSizeExceededException.java+40 0 added
    @@ -0,0 +1,40 @@
    +/**
    + * 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.cxf.attachment;
    +
    +public class HeaderSizeExceededException extends RuntimeException {
    +    private static final long serialVersionUID = -8976580055837650080L;
    +
    +    public HeaderSizeExceededException() {
    +        super();
    +    }
    +
    +    public HeaderSizeExceededException(String message) {
    +        super(message);
    +    }
    +
    +    public HeaderSizeExceededException(String message, Throwable cause) {
    +        super(message, cause);
    +    }
    +
    +    public HeaderSizeExceededException(Throwable cause) {
    +        super(cause);
    +    }
    +}
    
  • core/src/main/java/org/apache/cxf/message/MessageUtils.java+22 0 modified
    @@ -19,8 +19,11 @@
     
     package org.apache.cxf.message;
     
    +import java.util.logging.Logger;
    +
     import org.w3c.dom.Node;
     
    +import org.apache.cxf.common.logging.LogUtils;
     import org.apache.cxf.common.util.PropertyUtils;
     
     
    @@ -29,6 +32,8 @@
      */
     public final class MessageUtils {
     
    +    private static final Logger LOG = LogUtils.getL7dLogger(MessageUtils.class);
    +
         /**
          * Prevents instantiation.
          */
    @@ -142,6 +147,23 @@ public static boolean getContextualBoolean(Message m, String key, boolean defaul
             return defaultValue;
         }
     
    +    public static int getContextualInteger(Message m, String key, int defaultValue) {
    +        if (m != null) {
    +            Object o = m.getContextualProperty(key);
    +            if (o instanceof String) {
    +                try {
    +                    int i = Integer.parseInt((String)o);
    +                    if (i > 0) {
    +                        return i;
    +                    }
    +                } catch (NumberFormatException ex) {
    +                    LOG.warning("Incorrect integer value of " + o + " specified for: " + key);
    +                }
    +            }
    +        }
    +        return defaultValue;
    +    }
    +
         public static Object getContextualProperty(Message m, String propPreferred, String propDefault) {
             Object prop = null;
             if (m != null) {
    
  • rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/MessageContextImpl.java+7 0 modified
    @@ -45,6 +45,7 @@
     import org.apache.cxf.attachment.AttachmentDeserializer;
     import org.apache.cxf.attachment.AttachmentImpl;
     import org.apache.cxf.attachment.AttachmentUtil;
    +import org.apache.cxf.attachment.HeaderSizeExceededException;
     import org.apache.cxf.endpoint.Endpoint;
     import org.apache.cxf.helpers.CastUtils;
     import org.apache.cxf.interceptor.AttachmentOutInterceptor;
    @@ -64,6 +65,7 @@
     import org.apache.cxf.message.MessageUtils;
     
     public class MessageContextImpl implements MessageContext {
    +
         private Message m;
         public MessageContextImpl(Message m) {
             this.m = m;
    @@ -78,6 +80,8 @@ public Object get(Object key) {
                 } catch (CacheSizeExceededException e) {
                     m.getExchange().put("cxf.io.cacheinput", Boolean.FALSE);
                     throw new WebApplicationException(e, 413);
    +            } catch (HeaderSizeExceededException e) {
    +                throw new WebApplicationException(e, 413);
                 }
             }
             if (keyValue.equals("WRITE-" + Message.ATTACHMENTS)) {
    @@ -268,6 +272,8 @@ private MultipartBody createAttachments(String propertyName) {
                     m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MEMORY_THRESHOLD));
                 inMessage.put(AttachmentDeserializer.ATTACHMENT_MAX_SIZE,
                     m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MAX_SIZE));
    +            inMessage.put(AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE,
    +                m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE));
                 inMessage.setContent(InputStream.class,
                     m.getExchange().getInMessage().get("org.apache.cxf.multipart.embedded.input"));
                 inMessage.put(Message.CONTENT_TYPE,
    @@ -281,6 +287,7 @@ private MultipartBody createAttachments(String propertyName) {
             try {
                 Map<String, List<String>> headers
                     = CastUtils.cast((Map<?, ?>)inMessage.get(AttachmentDeserializer.ATTACHMENT_PART_HEADERS));
    +
                 Attachment first = new Attachment(AttachmentUtil.createAttachment(
                                          inMessage.getContent(InputStream.class),
                                          headers),
    
  • rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/multipart/Attachment.java+3 3 modified
    @@ -93,7 +93,7 @@ public Attachment(InputStream is, MultivaluedMap<String, String> headers) {
         public Attachment(String mediaType, Object object) {
             this(UUID.randomUUID().toString(), mediaType, object);
         }
    -    
    +
         public Attachment(String id, String mediaType, Object object) {
             this.object = object;
             if (id != null) {
    @@ -111,7 +111,7 @@ public Attachment(String id, InputStream is, ContentDisposition cd) {
             headers.putSingle("Content-Type", "application/octet-stream");
         }
     
    -    Attachment(MultivaluedMap<String, String> headers, DataHandler handler, Object object) {
    +    public Attachment(MultivaluedMap<String, String> headers, DataHandler handler, Object object) {
             this.headers = headers;
             this.handler = handler;
             this.object = object;
    @@ -128,7 +128,7 @@ public String getContentId() {
         }
     
         public MediaType getContentType() {
    -        String value = handler != null && handler.getContentType() != null ? handler.getContentType() 
    +        String value = handler != null && handler.getContentType() != null ? handler.getContentType()
                 : headers.getFirst("Content-Type");
             return value == null ? MediaType.TEXT_PLAIN_TYPE : JAXRSUtils.toMediaType(value);
         }
    
  • systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java+64 0 modified
    @@ -39,6 +39,7 @@
     import javax.imageio.ImageIO;
     import javax.mail.util.ByteArrayDataSource;
     import javax.ws.rs.core.MediaType;
    +import javax.ws.rs.core.MultivaluedHashMap;
     import javax.ws.rs.core.MultivaluedMap;
     import javax.ws.rs.core.Response;
     import javax.xml.bind.JAXBContext;
    @@ -53,6 +54,7 @@
     import org.apache.cxf.jaxrs.client.WebClient;
     import org.apache.cxf.jaxrs.ext.multipart.Attachment;
     import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition;
    +import org.apache.cxf.jaxrs.ext.multipart.InputStreamDataSource;
     import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
     import org.apache.cxf.jaxrs.impl.MetadataMap;
     import org.apache.cxf.jaxrs.provider.json.JSONProvider;
    @@ -937,6 +939,67 @@ public void testMultipartRequestTooLargeManyParts() throws Exception {
             }
         }
     
    +    // The large Content Disposition header will be rejected here
    +    @Test
    +    public void testLargeHeader() throws Exception {
    +        InputStream is1 =
    +            getClass().getResourceAsStream("/org/apache/cxf/systest/jaxrs/resources/java.jpg");
    +        String address = "http://localhost:" + PORT + "/bookstore/books/image";
    +        WebClient client = WebClient.create(address);
    +        client.type("multipart/mixed").accept("multipart/mixed");
    +        WebClient.getConfig(client).getRequestContext().put("support.type.as.multipart",
    +            "true");
    +
    +        StringBuilder sb = new StringBuilder();
    +        sb.append("form-data;");
    +        for (int i = 0; i < 10000; i++) {
    +            sb.append("aaaaaaaaaa");
    +        }
    +
    +        MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
    +        headers.putSingle("Content-ID", "root");
    +        headers.putSingle("Content-Type", "application/octet-stream");
    +        headers.putSingle("Content-Disposition", sb.toString());
    +        DataHandler handler = new DataHandler(new InputStreamDataSource(is1, "application/octet-stream"));
    +
    +        Attachment att = new Attachment(headers, handler, null);
    +        Response response = client.post(att);
    +        assertEquals(response.getStatus(), 413);
    +
    +        client.close();
    +    }
    +
    +    // The Content Disposition header will be accepted here, even though it is larger than the default,
    +    // as we have configured a larger value on the service side
    +    @Test
    +    public void testLargerThanDefaultHeader() throws Exception {
    +        InputStream is1 =
    +            getClass().getResourceAsStream("/org/apache/cxf/systest/jaxrs/resources/java.jpg");
    +        String address = "http://localhost:" + PORT + "/bookstore/books/image";
    +        WebClient client = WebClient.create(address);
    +        client.type("multipart/mixed").accept("multipart/mixed");
    +        WebClient.getConfig(client).getRequestContext().put("support.type.as.multipart",
    +            "true");
    +
    +        StringBuilder sb = new StringBuilder();
    +        sb.append("form-data;");
    +        for (int i = 0; i < 35; i++) {
    +            sb.append("aaaaaaaaaa");
    +        }
    +
    +        MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
    +        headers.putSingle("Content-ID", "root");
    +        headers.putSingle("Content-Type", "application/octet-stream");
    +        headers.putSingle("Content-Disposition", sb.toString());
    +        DataHandler handler = new DataHandler(new InputStreamDataSource(is1, "application/octet-stream"));
    +
    +        Attachment att = new Attachment(headers, handler, null);
    +        Response response = client.post(att);
    +        assertEquals(response.getStatus(), 200);
    +
    +        client.close();
    +    }
    +
         private void doAddBook(String address, String resourceName, int status) throws Exception {
             doAddBook("multipart/related", address, resourceName, status);
         }
    @@ -1018,4 +1081,5 @@ private String stripXmlInstructionIfNeeded(String str) {
             }
             return str;
         }
    +
     }
    
  • systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartServer.java+1 0 modified
    @@ -40,6 +40,7 @@ protected void run() {
             Map<String, Object> props = new HashMap<>();
             props.put(AttachmentDeserializer.ATTACHMENT_MAX_SIZE, String.valueOf(1024 * 10));
             props.put(AttachmentDeserializer.ATTACHMENT_MEMORY_THRESHOLD, String.valueOf(1024 * 5));
    +        props.put(AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE, String.valueOf(400));
             sf.setProperties(props);
             //default lifecycle is per-request, change it to singleton
             sf.setResourceProvider(MultipartStore.class,
    
896bd961cbbb

CXF-7507 - Put a configurable limit on the size of attachment headers

https://github.com/apache/cxfColm O hEigeartaighOct 3, 2017via ghsa
8 files changed · +165 7
  • core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java+24 0 modified
    @@ -29,17 +29,20 @@
     import java.util.Map;
     import java.util.Set;
     import java.util.TreeMap;
    +import java.util.logging.Logger;
     import java.util.regex.Matcher;
     import java.util.regex.Pattern;
     
     import javax.activation.DataSource;
     
    +import org.apache.cxf.common.logging.LogUtils;
     import org.apache.cxf.common.util.StringUtils;
     import org.apache.cxf.helpers.HttpHeaderHelper;
     import org.apache.cxf.helpers.IOUtils;
     import org.apache.cxf.io.CachedOutputStream;
     import org.apache.cxf.message.Attachment;
     import org.apache.cxf.message.Message;
    +import org.apache.cxf.message.MessageUtils;
     
     public class AttachmentDeserializer {
         public static final String ATTACHMENT_PART_HEADERS = AttachmentDeserializer.class.getName() + ".headers";
    @@ -49,6 +52,12 @@ public class AttachmentDeserializer {
     
         public static final String ATTACHMENT_MAX_SIZE = "attachment-max-size";
     
    +    /**
    +     * The maximum MIME Header Length. The default is 300.
    +     */
    +    public static final String ATTACHMENT_MAX_HEADER_SIZE = "attachment-max-header-size";
    +    public static final int DEFAULT_MAX_HEADER_SIZE = 300;
    +
         public static final int THRESHOLD = 1024 * 100; //100K (byte unit)
     
         private static final Pattern CONTENT_TYPE_BOUNDARY_PATTERN = Pattern.compile("boundary=\"?([^\";]*)");
    @@ -58,6 +67,8 @@ public class AttachmentDeserializer {
         private static final Pattern INPUT_STREAM_BOUNDARY_PATTERN =
                 Pattern.compile("^--(\\S*)$", Pattern.MULTILINE);
     
    +    private static final Logger LOG = LogUtils.getL7dLogger(AttachmentDeserializer.class);
    +
         private boolean lazyLoading = true;
     
         private int pbAmount = 2048;
    @@ -79,13 +90,19 @@ public class AttachmentDeserializer {
         private Set<DelegatingInputStream> loaded = new HashSet<DelegatingInputStream>();
         private List<String> supportedTypes;
     
    +    private int maxHeaderLength = DEFAULT_MAX_HEADER_SIZE;
    +
         public AttachmentDeserializer(Message message) {
             this(message, Collections.singletonList("multipart/related"));
         }
     
         public AttachmentDeserializer(Message message, List<String> supportedTypes) {
             this.message = message;
             this.supportedTypes = supportedTypes;
    +
    +        // Get the maximum Header length from configuration
    +        maxHeaderLength = MessageUtils.getContextualInteger(message, ATTACHMENT_MAX_HEADER_SIZE,
    +                                                            DEFAULT_MAX_HEADER_SIZE);
         }
         
         public void initializeAttachments() throws IOException {
    @@ -279,6 +296,7 @@ private Attachment createAttachment(Map<String, List<String>> headers) throws IO
                 new DelegatingInputStream(new MimeBodyPartInputStream(stream, boundary, pbAmount),
                                           this);
             createCount++;
    +
             return AttachmentUtil.createAttachment(partStream, headers);
         }
     
    @@ -327,6 +345,7 @@ private Map<String, List<String>> loadPartHeaders(InputStream in) throws IOExcep
             StringBuilder buffer = new StringBuilder(128);
             StringBuilder b = new StringBuilder(128);
             Map<String, List<String>> heads = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER);
    +
             // loop until we hit the end or a null line
             while (readLine(in, b)) {
                 // lines beginning with white space get special handling
    @@ -373,6 +392,11 @@ private boolean readLine(InputStream in, StringBuilder buffer) throws IOExceptio
                     // just add to the buffer
                     buffer.append((char)c);
                 }
    +
    +            if (buffer.length() > maxHeaderLength) {
    +                LOG.fine("The attachment header size has exceeded the configured parameter: " + maxHeaderLength);
    +                throw new HeaderSizeExceededException();
    +            }
             }
     
             // no characters found...this was either an eof or a null line.
    
  • core/src/main/java/org/apache/cxf/attachment/ContentDisposition.java+1 1 modified
    @@ -28,7 +28,7 @@
     
     public class ContentDisposition {
         private static final String CD_HEADER_PARAMS_EXPRESSION =
    -        "(([\\w-]+( )?\\*?=( )?\"[^\"]+\")|([\\w-]+( )?\\*?=( )?[^;]+))";
    +       "[\\w-]++( )?\\*?=( )?((\"[^\"]++\")|([^;]+))";
         private static final Pattern CD_HEADER_PARAMS_PATTERN =
                 Pattern.compile(CD_HEADER_PARAMS_EXPRESSION);
     
    
  • core/src/main/java/org/apache/cxf/attachment/HeaderSizeExceededException.java+40 0 added
    @@ -0,0 +1,40 @@
    +/**
    + * 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.cxf.attachment;
    +
    +public class HeaderSizeExceededException extends RuntimeException {
    +    private static final long serialVersionUID = -8976580055837650080L;
    +
    +    public HeaderSizeExceededException() {
    +        super();
    +    }
    +
    +    public HeaderSizeExceededException(String message) {
    +        super(message);
    +    }
    +
    +    public HeaderSizeExceededException(String message, Throwable cause) {
    +        super(message, cause);
    +    }
    +
    +    public HeaderSizeExceededException(Throwable cause) {
    +        super(cause);
    +    }
    +}
    
  • core/src/main/java/org/apache/cxf/message/MessageUtils.java+23 1 modified
    @@ -19,8 +19,11 @@
     
     package org.apache.cxf.message;
     
    +import java.util.logging.Logger;
    +
     import org.w3c.dom.Node;
     
    +import org.apache.cxf.common.logging.LogUtils;
     import org.apache.cxf.common.util.PropertyUtils;
     
     
    @@ -29,6 +32,8 @@
      */
     public final class MessageUtils {
     
    +    private static final Logger LOG = LogUtils.getL7dLogger(MessageUtils.class);
    +
         /**
          * Prevents instantiation.
          */
    @@ -139,7 +144,24 @@ public static boolean getContextualBoolean(Message m, String key, boolean defaul
             }
             return defaultValue;
         }
    -    
    +
    +    public static int getContextualInteger(Message m, String key, int defaultValue) {
    +        if (m != null) {
    +            Object o = m.getContextualProperty(key);
    +            if (o instanceof String) {
    +                try {
    +                    int i = Integer.parseInt((String)o);
    +                    if (i > 0) {
    +                        return i;
    +                    }
    +                } catch (NumberFormatException ex) {
    +                    LOG.warning("Incorrect integer value of " + o + " specified for: " + key);
    +                }
    +            }
    +        }
    +        return defaultValue;
    +    }
    +
         public static Object getContextualProperty(Message m, String propPreferred, String propDefault) {
             Object prop = null;
             if (m != null) {
    
  • rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/MessageContextImpl.java+8 1 modified
    @@ -45,6 +45,7 @@
     import org.apache.cxf.attachment.AttachmentDeserializer;
     import org.apache.cxf.attachment.AttachmentImpl;
     import org.apache.cxf.attachment.AttachmentUtil;
    +import org.apache.cxf.attachment.HeaderSizeExceededException;
     import org.apache.cxf.endpoint.Endpoint;
     import org.apache.cxf.helpers.CastUtils;
     import org.apache.cxf.interceptor.AttachmentOutInterceptor;
    @@ -64,6 +65,7 @@
     import org.apache.cxf.message.MessageUtils;
     
     public class MessageContextImpl implements MessageContext {
    +
         private Message m;
         public MessageContextImpl(Message m) {
             this.m = m;
    @@ -78,6 +80,8 @@ public Object get(Object key) {
                 } catch (CacheSizeExceededException e) {
                     m.getExchange().put("cxf.io.cacheinput", Boolean.FALSE);
                     throw new WebApplicationException(e, 413);
    +            } catch (HeaderSizeExceededException e) {
    +                throw new WebApplicationException(e, 413);
                 }
             }
             if (keyValue.equals("WRITE-" + Message.ATTACHMENTS)) {
    @@ -269,7 +273,9 @@ private MultipartBody createAttachments(String propertyName) {
                     m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MEMORY_THRESHOLD));
                 inMessage.put(AttachmentDeserializer.ATTACHMENT_MAX_SIZE,
                     m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MAX_SIZE));
    -            inMessage.setContent(InputStream.class, 
    +            inMessage.put(AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE,
    +                m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE));
    +            inMessage.setContent(InputStream.class,
                     m.getExchange().getInMessage().get("org.apache.cxf.multipart.embedded.input"));
                 inMessage.put(Message.CONTENT_TYPE, 
                     m.getExchange().getInMessage().get("org.apache.cxf.multipart.embedded.ctype").toString());
    @@ -282,6 +288,7 @@ private MultipartBody createAttachments(String propertyName) {
             try {
                 Map<String, List<String>> headers 
                     = CastUtils.cast((Map<?, ?>)inMessage.get(AttachmentDeserializer.ATTACHMENT_PART_HEADERS));
    +
                 Attachment first = new Attachment(AttachmentUtil.createAttachment(
                                          inMessage.getContent(InputStream.class), 
                                          headers),
    
  • rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/multipart/Attachment.java+4 4 modified
    @@ -93,7 +93,7 @@ public Attachment(InputStream is, MultivaluedMap<String, String> headers) {
         public Attachment(String mediaType, Object object) {
             this(UUID.randomUUID().toString(), mediaType, object);
         }
    -    
    +
         public Attachment(String id, String mediaType, Object object) {
             this.object = object;
             if (id != null) {
    @@ -110,8 +110,8 @@ public Attachment(String id, InputStream is, ContentDisposition cd) {
             headers.putSingle("Content-ID", id);
             headers.putSingle("Content-Type", "application/octet-stream");
         }
    -    
    -    Attachment(MultivaluedMap<String, String> headers, DataHandler handler, Object object) {
    +
    +    public Attachment(MultivaluedMap<String, String> headers, DataHandler handler, Object object) {
             this.headers = headers;
             this.handler = handler;
             this.object = object;
    @@ -128,7 +128,7 @@ public String getContentId() {
         }
     
         public MediaType getContentType() {
    -        String value = handler != null && handler.getContentType() != null ? handler.getContentType() 
    +        String value = handler != null && handler.getContentType() != null ? handler.getContentType()
                 : headers.getFirst("Content-Type");
             return value == null ? MediaType.TEXT_PLAIN_TYPE : JAXRSUtils.toMediaType(value);
         }
    
  • systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java+64 0 modified
    @@ -39,6 +39,7 @@
     import javax.imageio.ImageIO;
     import javax.mail.util.ByteArrayDataSource;
     import javax.ws.rs.core.MediaType;
    +import javax.ws.rs.core.MultivaluedHashMap;
     import javax.ws.rs.core.MultivaluedMap;
     import javax.ws.rs.core.Response;
     import javax.xml.bind.JAXBContext;
    @@ -53,6 +54,7 @@
     import org.apache.cxf.jaxrs.client.WebClient;
     import org.apache.cxf.jaxrs.ext.multipart.Attachment;
     import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition;
    +import org.apache.cxf.jaxrs.ext.multipart.InputStreamDataSource;
     import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
     import org.apache.cxf.jaxrs.impl.MetadataMap;
     import org.apache.cxf.jaxrs.provider.json.JSONProvider;
    @@ -937,6 +939,67 @@ public void testMultipartRequestTooLargeManyParts() throws Exception {
             }
         }
     
    +    // The large Content Disposition header will be rejected here
    +    @Test
    +    public void testLargeHeader() throws Exception {
    +        InputStream is1 =
    +            getClass().getResourceAsStream("/org/apache/cxf/systest/jaxrs/resources/java.jpg");
    +        String address = "http://localhost:" + PORT + "/bookstore/books/image";
    +        WebClient client = WebClient.create(address);
    +        client.type("multipart/mixed").accept("multipart/mixed");
    +        WebClient.getConfig(client).getRequestContext().put("support.type.as.multipart",
    +            "true");
    +
    +        StringBuilder sb = new StringBuilder();
    +        sb.append("form-data;");
    +        for (int i = 0; i < 10000; i++) {
    +            sb.append("aaaaaaaaaa");
    +        }
    +
    +        MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
    +        headers.putSingle("Content-ID", "root");
    +        headers.putSingle("Content-Type", "application/octet-stream");
    +        headers.putSingle("Content-Disposition", sb.toString());
    +        DataHandler handler = new DataHandler(new InputStreamDataSource(is1, "application/octet-stream"));
    +
    +        Attachment att = new Attachment(headers, handler, null);
    +        Response response = client.post(att);
    +        assertEquals(response.getStatus(), 413);
    +
    +        client.close();
    +    }
    +
    +    // The Content Disposition header will be accepted here, even though it is larger than the default,
    +    // as we have configured a larger value on the service side
    +    @Test
    +    public void testLargerThanDefaultHeader() throws Exception {
    +        InputStream is1 =
    +            getClass().getResourceAsStream("/org/apache/cxf/systest/jaxrs/resources/java.jpg");
    +        String address = "http://localhost:" + PORT + "/bookstore/books/image";
    +        WebClient client = WebClient.create(address);
    +        client.type("multipart/mixed").accept("multipart/mixed");
    +        WebClient.getConfig(client).getRequestContext().put("support.type.as.multipart",
    +            "true");
    +
    +        StringBuilder sb = new StringBuilder();
    +        sb.append("form-data;");
    +        for (int i = 0; i < 35; i++) {
    +            sb.append("aaaaaaaaaa");
    +        }
    +
    +        MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
    +        headers.putSingle("Content-ID", "root");
    +        headers.putSingle("Content-Type", "application/octet-stream");
    +        headers.putSingle("Content-Disposition", sb.toString());
    +        DataHandler handler = new DataHandler(new InputStreamDataSource(is1, "application/octet-stream"));
    +
    +        Attachment att = new Attachment(headers, handler, null);
    +        Response response = client.post(att);
    +        assertEquals(response.getStatus(), 200);
    +
    +        client.close();
    +    }
    +
         private void doAddBook(String address, String resourceName, int status) throws Exception {
             doAddBook("multipart/related", address, resourceName, status);
         }
    @@ -1018,4 +1081,5 @@ private String stripXmlInstructionIfNeeded(String str) {
             }
             return str;
         }
    +
     }
    
  • systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartServer.java+1 0 modified
    @@ -40,6 +40,7 @@ protected void run() {
             Map<String, Object> props = new HashMap<String, Object>();
             props.put(AttachmentDeserializer.ATTACHMENT_MAX_SIZE, String.valueOf(1024 * 10));
             props.put(AttachmentDeserializer.ATTACHMENT_MEMORY_THRESHOLD, String.valueOf(1024 * 5));
    +        props.put(AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE, String.valueOf(400));
             sf.setProperties(props);
             //default lifecycle is per-request, change it to singleton
             sf.setResourceProvider(MultipartStore.class,
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

25

News mentions

0

No linked articles in our index yet.