VYPR
High severityNVD Advisory· Published Jun 16, 2025· Updated Nov 3, 2025

Apache Tomcat: FileUpload large number of parts with headers DoS

CVE-2025-48988

Description

Allocation of Resources Without Limits or Throttling vulnerability in Apache Tomcat.

This issue affects Apache Tomcat: from 11.0.0-M1 through 11.0.7, from 10.1.0-M1 through 10.1.41, from 9.0.0.M1 through 9.0.105. The following versions were EOL at the time the CVE was created but are known to be affected: 8.5.0 though 8.5.100. Other, older, EOL versions may also be affected.

Users are recommended to upgrade to version 11.0.8, 10.1.42 or 9.0.106, which fix the issue.

AI Insight

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

Apache Tomcat is vulnerable to resource exhaustion via unthrottled multipart request processing, allowing denial-of-service attacks.

Vulnerability

CVE-2025-48988 is an Allocation of Resources Without Limits or Throttling vulnerability in Apache Tomcat's handling of multipart requests. The root cause is the lack of configured limits on the number of parts and part header sizes within such requests, allowing an attacker to consume excessive server resources (CPU, memory, or disk) without proper rate-limiting. The fix introduces two new configuration parameters: maxPartCount (default 10) and maxPartHeaderSize (default 512 bytes) in the Connector to provide finer-grained control [4].

Exploitation

An attacker does not need authentication to exploit this vulnerability; it is accessible over HTTP or HTTPS via any endpoint that accepts multipart form data. By sending a specially crafted multipart request with an abnormally large number of parts or parts with oversized headers, the attacker can trigger unbounded resource allocation on the server. The vulnerability exists across affected versions (11.0.0-M1 through 11.0.7, 10.1.0-M1 through 10.1.41, 9.0.0-M1 through 9.0.105), as well as in the end-of-life (EOL) branches 8.5.x and earlier [1][2][3].

Impact

Successful exploitation leads to resource exhaustion, potentially resulting in a denial-of-service (DoS) condition. The server may become unresponsive or crash, impacting availability for legitimate users. Since the attack does not require authentication and can be launched over the network, it poses a significant risk to public-facing Tomcat instances.

Mitigation

The Apache Tomcat project has released fixed versions 11.0.8, 10.1.42, and 9.0.106 that resolve the issue by introducing the maxPartCount and maxPartHeaderSize limits [1][2][3]. Users are strongly recommended to upgrade to these or later versions immediately. For EOL branches (e.g., 8.5.x), no patches are provided, and users should migrate to a supported line.

AI Insight generated on May 20, 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.tomcat:tomcat-catalinaMaven
>= 11.0.0-M1, < 11.0.811.0.8
org.apache.tomcat:tomcat-catalinaMaven
>= 10.1.0-M1, < 10.1.4210.1.42
org.apache.tomcat:tomcat-catalinaMaven
>= 9.0.0.M1, < 9.0.1069.0.106
org.apache.tomcat.embed:tomcat-embed-coreMaven
>= 11.0.0-M1, < 11.0.811.0.8
org.apache.tomcat.embed:tomcat-embed-coreMaven
>= 10.1.0-M1, < 10.1.4210.1.42
org.apache.tomcat.embed:tomcat-embed-coreMaven
>= 9.0.0.M1, < 9.0.1069.0.106
org.apache.tomcat:tomcat-catalinaMaven
>= 8.5.0, <= 8.5.100
org.apache.tomcat.embed:tomcat-embed-coreMaven
>= 8.5.0, <= 8.5.100

Affected products

58

Patches

3
2b0ab14fb55d

Provide finder grained control of multi-part requests

https://github.com/apache/tomcatMark ThomasJun 3, 2025via ghsa
6 files changed · +85 6
  • java/org/apache/catalina/connector/Connector.java+24 0 modified
    @@ -210,6 +210,10 @@ public Connector(ProtocolHandler protocolHandler) {
          */
         protected int maxParameterCount = 1000;
     
    +    private int maxPartCount = 10;
    +
    +    private int maxPartHeaderSize = 512;
    +
         /**
          * Maximum size of a POST which will be automatically parsed by the container. 2 MiB by default.
          */
    @@ -479,6 +483,26 @@ public void setMaxParameterCount(int maxParameterCount) {
         }
     
     
    +    public int getMaxPartCount() {
    +        return maxPartCount;
    +    }
    +
    +
    +    public void setMaxPartCount(int maxPartCount) {
    +        this.maxPartCount = maxPartCount;
    +    }
    +
    +
    +    public int getMaxPartHeaderSize() {
    +        return maxPartHeaderSize;
    +    }
    +
    +
    +    public void setMaxPartHeaderSize(int maxPartHeaderSize) {
    +        this.maxPartHeaderSize = maxPartHeaderSize;
    +    }
    +
    +
         /**
          * @return the maximum size of a POST which will be automatically parsed by the container.
          */
    
  • java/org/apache/catalina/connector/Request.java+22 6 modified
    @@ -2490,13 +2490,29 @@ private void parseParts(boolean explicit) {
             upload.setFileItemFactory(factory);
             upload.setFileSizeMax(mce.getMaxFileSize());
             upload.setSizeMax(mce.getMaxRequestSize());
    -        if (maxParameterCount > -1) {
    -            // There is a limit. The limit for parts needs to be reduced by
    -            // the number of parameters we have already parsed.
    -            // Must be under the limit else parsing parameters would have
    -            // triggered an exception.
    -            upload.setFileCountMax(maxParameterCount - parameters.size());
    +        upload.setPartHeaderSizeMax(connector.getMaxPartHeaderSize());
    +        /*
    +         * There are two independent limits on the number of parts.
    +         *
    +         * 1. The limit based on parameters. This is maxParameterCount less the number of parameters already processed.
    +         *
    +         * 2. The limit based on parts. This is maxPartCount.
    +         *
    +         * The lower of these two limits will be applied to this request.
    +         *
    +         * Note: Either of both limits may be set to -1 (unlimited).
    +         */
    +        int partLimit = maxParameterCount;
    +        if (partLimit > -1) {
    +            partLimit = partLimit - parameters.size();
    +        }
    +        int maxPartCount = connector.getMaxPartCount();
    +        if (maxPartCount > -1) {
    +            if (partLimit < 0 || partLimit > maxPartCount) {
    +                partLimit = maxPartCount;
    +            }
             }
    +        upload.setFileCountMax(partLimit);
     
             parts = new ArrayList<>();
             try {
    
  • webapps/docs/changelog.xml+7 0 modified
    @@ -150,6 +150,13 @@
             <code>BlockingQueue</code> implementation. Pull request provided by
             Paulo Almeida. (markt)
           </scode>
    +      <add>
    +        Provide finer grained control of multi-part request processing via two
    +        new attributes on the <code>Connector</code> element.
    +        <code>maxPartCount</code> limits the total number of parts in a
    +        multi-part request and <code>maxPartHeaderSize</code> limits the size of
    +        the headers provided with each part. (markt)
    +      </add>
         </changelog>
       </subsection>
       <subsection name="Jasper">
    
  • webapps/docs/config/ajp.xml+15 0 modified
    @@ -185,6 +185,21 @@
           default of 1000 is used.</p>
         </attribute>
     
    +    <attribute name="maxPartCount" required="false">
    +      <p>The maximum total number of parts permitted in a request where the
    +      content type is <code>multipart/form-data</code>. This limit is in
    +      addition to <code>maxParameterCount</code>. Requests that exceed this
    +      limit will be rejected. A value of less than 0 means no limit. If not
    +      specified, a default of 10 is used.</p>
    +    </attribute>
    +
    +    <attribute name="maxPartHeaderSize" required="false">
    +      <p>The maximum number of header bytes permitted per part in a request
    +      where the content type is <code>multipart/form-data</code>. Requests that
    +      exceed this limit will be rejected. A value of less than 0 means no limit.
    +      If not specified, a default of 512 is used.</p>
    +    </attribute>
    +
         <attribute name="maxPostSize" required="false">
           <p>The maximum size in bytes of the POST which will be handled by
           the container FORM URL parameter parsing. The limit can be disabled by
    
  • webapps/docs/config/http2.xml+2 0 modified
    @@ -240,6 +240,8 @@
         <li>maxHttpHeaderSize</li>
         <li>maxHttpRequestHeaderSize</li>
         <li>maxParameterCount</li>
    +    <li>maxPartCount</li>
    +    <li>maxPartHeaderSize</li>
         <li>maxPostSize</li>
         <li>maxSavePostSize</li>
         <li>maxTrailerSize</li>
    
  • webapps/docs/config/http.xml+15 0 modified
    @@ -181,6 +181,21 @@
           default of 1000 is used.</p>
         </attribute>
     
    +    <attribute name="maxPartCount" required="false">
    +      <p>The maximum total number of parts permitted in a request where the
    +      content type is <code>multipart/form-data</code>. This limit is in
    +      addition to <code>maxParameterCount</code>. Requests that exceed this
    +      limit will be rejected. A value of less than 0 means no limit. If not
    +      specified, a default of 10 is used.</p>
    +    </attribute>
    +
    +    <attribute name="maxPartHeaderSize" required="false">
    +      <p>The maximum number of header bytes permitted per part in a request
    +      where the content type is <code>multipart/form-data</code>. Requests that
    +      exceed this limit will be rejected. A value of less than 0 means no limit.
    +      If not specified, a default of 512 is used.</p>
    +    </attribute>
    +
         <attribute name="maxPostSize" required="false">
           <p>The maximum size in bytes of the POST which will be handled by
           the container FORM URL parameter parsing. The limit can be disabled by
    
cdde8e655bc1

Provide finder grained control of multi-part requests

https://github.com/apache/tomcatMark ThomasJun 3, 2025via ghsa
6 files changed · +85 6
  • java/org/apache/catalina/connector/Connector.java+24 0 modified
    @@ -212,6 +212,10 @@ public Connector(ProtocolHandler protocolHandler) {
          */
         protected int maxParameterCount = 10000;
     
    +    private int maxPartCount = 10;
    +
    +    private int maxPartHeaderSize = 512;
    +
         /**
          * Maximum size of a POST which will be automatically parsed by the container. 2 MiB by default.
          */
    @@ -482,6 +486,26 @@ public void setMaxParameterCount(int maxParameterCount) {
         }
     
     
    +    public int getMaxPartCount() {
    +        return maxPartCount;
    +    }
    +
    +
    +    public void setMaxPartCount(int maxPartCount) {
    +        this.maxPartCount = maxPartCount;
    +    }
    +
    +
    +    public int getMaxPartHeaderSize() {
    +        return maxPartHeaderSize;
    +    }
    +
    +
    +    public void setMaxPartHeaderSize(int maxPartHeaderSize) {
    +        this.maxPartHeaderSize = maxPartHeaderSize;
    +    }
    +
    +
         /**
          * @return the maximum size of a POST which will be automatically parsed by the container.
          */
    
  • java/org/apache/catalina/connector/Request.java+22 6 modified
    @@ -2589,13 +2589,29 @@ private void parseParts(boolean explicit) {
                 upload.setFileItemFactory(factory);
                 upload.setFileSizeMax(mce.getMaxFileSize());
                 upload.setSizeMax(mce.getMaxRequestSize());
    -            if (maxParameterCount > -1) {
    -                // There is a limit. The limit for parts needs to be reduced by
    -                // the number of parameters we have already parsed.
    -                // Must be under the limit else parsing parameters would have
    -                // triggered an exception.
    -                upload.setFileCountMax(maxParameterCount - parameters.size());
    +            upload.setPartHeaderSizeMax(connector.getMaxPartHeaderSize());
    +            /*
    +             * There are two independent limits on the number of parts.
    +             *
    +             * 1. The limit based on parameters. This is maxParameterCount less the number of parameters already processed.
    +             *
    +             * 2. The limit based on parts. This is maxPartCount.
    +             *
    +             * The lower of these two limits will be applied to this request.
    +             *
    +             * Note: Either of both limits may be set to -1 (unlimited).
    +             */
    +            int partLimit = maxParameterCount;
    +            if (partLimit > -1) {
    +                partLimit = partLimit - parameters.size();
    +            }
    +            int maxPartCount = connector.getMaxPartCount();
    +            if (maxPartCount > -1) {
    +                if (partLimit < 0 || partLimit > maxPartCount) {
    +                    partLimit = maxPartCount;
    +                }
                 }
    +            upload.setFileCountMax(partLimit);
     
                 parts = new ArrayList<>();
                 try {
    
  • webapps/docs/changelog.xml+7 0 modified
    @@ -146,6 +146,13 @@
             <code>BlockingQueue</code> implementation. Pull request provided by
             Paulo Almeida. (markt)
           </scode>
    +      <add>
    +        Provide finer grained control of multi-part request processing via two
    +        new attributes on the <code>Connector</code> element.
    +        <code>maxPartCount</code> limits the total number of parts in a
    +        multi-part request and <code>maxPartHeaderSize</code> limits the size of
    +        the headers provided with each part. (markt)
    +      </add>
         </changelog>
       </subsection>
       <subsection name="Jasper">
    
  • webapps/docs/config/ajp.xml+15 0 modified
    @@ -188,6 +188,21 @@
           exceed the limit.</p>
         </attribute>
     
    +    <attribute name="maxPartCount" required="false">
    +      <p>The maximum total number of parts permitted in a request where the
    +      content type is <code>multipart/form-data</code>. This limit is in
    +      addition to <code>maxParameterCount</code>. Requests that exceed this
    +      limit will be rejected. A value of less than 0 means no limit. If not
    +      specified, a default of 10 is used.</p>
    +    </attribute>
    +
    +    <attribute name="maxPartHeaderSize" required="false">
    +      <p>The maximum number of header bytes permitted per part in a request
    +      where the content type is <code>multipart/form-data</code>. Requests that
    +      exceed this limit will be rejected. A value of less than 0 means no limit.
    +      If not specified, a default of 512 is used.</p>
    +    </attribute>
    +
         <attribute name="maxPostSize" required="false">
           <p>The maximum size in bytes of the POST which will be handled by
           the container FORM URL parameter parsing. The limit can be disabled by
    
  • webapps/docs/config/http2.xml+2 0 modified
    @@ -240,6 +240,8 @@
         <li>maxHttpHeaderSize</li>
         <li>maxHttpRequestHeaderSize</li>
         <li>maxParameterCount</li>
    +    <li>maxPartCount</li>
    +    <li>maxPartHeaderSize</li>
         <li>maxPostSize</li>
         <li>maxSavePostSize</li>
         <li>maxTrailerSize</li>
    
  • webapps/docs/config/http.xml+15 0 modified
    @@ -184,6 +184,21 @@
           exceed the limit.</p>
         </attribute>
     
    +    <attribute name="maxPartCount" required="false">
    +      <p>The maximum total number of parts permitted in a request where the
    +      content type is <code>multipart/form-data</code>. This limit is in
    +      addition to <code>maxParameterCount</code>. Requests that exceed this
    +      limit will be rejected. A value of less than 0 means no limit. If not
    +      specified, a default of 10 is used.</p>
    +    </attribute>
    +
    +    <attribute name="maxPartHeaderSize" required="false">
    +      <p>The maximum number of header bytes permitted per part in a request
    +      where the content type is <code>multipart/form-data</code>. Requests that
    +      exceed this limit will be rejected. A value of less than 0 means no limit.
    +      If not specified, a default of 512 is used.</p>
    +    </attribute>
    +
         <attribute name="maxPostSize" required="false">
           <p>The maximum size in bytes of the POST which will be handled by
           the container FORM URL parameter parsing. The limit can be disabled by
    
ee8042ffce4c

Provide finder grained control of multi-part requests

https://github.com/apache/tomcatMark ThomasJun 3, 2025via ghsa
6 files changed · +85 6
  • java/org/apache/catalina/connector/Connector.java+24 0 modified
    @@ -204,6 +204,10 @@ public Connector(ProtocolHandler protocolHandler) {
          */
         protected int maxParameterCount = 10000;
     
    +    private int maxPartCount = 10;
    +
    +    private int maxPartHeaderSize = 512;
    +
         /**
          * Maximum size of a POST which will be automatically parsed by the container. 2 MiB by default.
          */
    @@ -463,6 +467,26 @@ public void setMaxParameterCount(int maxParameterCount) {
         }
     
     
    +    public int getMaxPartCount() {
    +        return maxPartCount;
    +    }
    +
    +
    +    public void setMaxPartCount(int maxPartCount) {
    +        this.maxPartCount = maxPartCount;
    +    }
    +
    +
    +    public int getMaxPartHeaderSize() {
    +        return maxPartHeaderSize;
    +    }
    +
    +
    +    public void setMaxPartHeaderSize(int maxPartHeaderSize) {
    +        this.maxPartHeaderSize = maxPartHeaderSize;
    +    }
    +
    +
         /**
          * @return the maximum size of a POST which will be automatically parsed by the container.
          */
    
  • java/org/apache/catalina/connector/Request.java+22 6 modified
    @@ -2630,13 +2630,29 @@ private void parseParts(boolean explicit) {
                 upload.setFileItemFactory(factory);
                 upload.setFileSizeMax(mce.getMaxFileSize());
                 upload.setSizeMax(mce.getMaxRequestSize());
    -            if (maxParameterCount > -1) {
    -                // There is a limit. The limit for parts needs to be reduced by
    -                // the number of parameters we have already parsed.
    -                // Must be under the limit else parsing parameters would have
    -                // triggered an exception.
    -                upload.setFileCountMax(maxParameterCount - parameters.size());
    +            upload.setPartHeaderSizeMax(connector.getMaxPartHeaderSize());
    +            /*
    +             * There are two independent limits on the number of parts.
    +             *
    +             * 1. The limit based on parameters. This is maxParameterCount less the number of parameters already processed.
    +             *
    +             * 2. The limit based on parts. This is maxPartCount.
    +             *
    +             * The lower of these two limits will be applied to this request.
    +             *
    +             * Note: Either of both limits may be set to -1 (unlimited).
    +             */
    +            int partLimit = maxParameterCount;
    +            if (partLimit > -1) {
    +                partLimit = partLimit - parameters.size();
    +            }
    +            int maxPartCount = connector.getMaxPartCount();
    +            if (maxPartCount > -1) {
    +                if (partLimit < 0 || partLimit > maxPartCount) {
    +                    partLimit = maxPartCount;
    +                }
                 }
    +            upload.setFileCountMax(partLimit);
     
                 parts = new ArrayList<>();
                 try {
    
  • webapps/docs/changelog.xml+7 0 modified
    @@ -146,6 +146,13 @@
             <code>BlockingQueue</code> implementation. Pull request provided by
             Paulo Almeida. (markt)
           </scode>
    +      <add>
    +        Provide finer grained control of multi-part request processing via two
    +        new attributes on the <code>Connector</code> element.
    +        <code>maxPartCount</code> limits the total number of parts in a
    +        multi-part request and <code>maxPartHeaderSize</code> limits the size of
    +        the headers provided with each part. (markt)
    +      </add>
         </changelog>
       </subsection>
       <subsection name="Jasper">
    
  • webapps/docs/config/ajp.xml+15 0 modified
    @@ -175,6 +175,21 @@
           exceed the limit.</p>
         </attribute>
     
    +    <attribute name="maxPartCount" required="false">
    +      <p>The maximum total number of parts permitted in a request where the
    +      content type is <code>multipart/form-data</code>. This limit is in
    +      addition to <code>maxParameterCount</code>. Requests that exceed this
    +      limit will be rejected. A value of less than 0 means no limit. If not
    +      specified, a default of 10 is used.</p>
    +    </attribute>
    +
    +    <attribute name="maxPartHeaderSize" required="false">
    +      <p>The maximum number of header bytes permitted per part in a request
    +      where the content type is <code>multipart/form-data</code>. Requests that
    +      exceed this limit will be rejected. A value of less than 0 means no limit.
    +      If not specified, a default of 512 is used.</p>
    +    </attribute>
    +
         <attribute name="maxPostSize" required="false">
           <p>The maximum size in bytes of the POST which will be handled by
           the container FORM URL parameter parsing. The limit can be disabled by
    
  • webapps/docs/config/http2.xml+2 0 modified
    @@ -317,6 +317,8 @@
       <ul>
         <li>maxCookieCount</li>
         <li>maxParameterCount</li>
    +    <li>maxPartCount</li>
    +    <li>maxPartHeaderSize</li>
         <li>maxPostSize</li>
         <li>maxSavePostSize</li>
         <li>server</li>
    
  • webapps/docs/config/http.xml+15 0 modified
    @@ -173,6 +173,21 @@
           exceed the limit.</p>
         </attribute>
     
    +    <attribute name="maxPartCount" required="false">
    +      <p>The maximum total number of parts permitted in a request where the
    +      content type is <code>multipart/form-data</code>. This limit is in
    +      addition to <code>maxParameterCount</code>. Requests that exceed this
    +      limit will be rejected. A value of less than 0 means no limit. If not
    +      specified, a default of 10 is used.</p>
    +    </attribute>
    +
    +    <attribute name="maxPartHeaderSize" required="false">
    +      <p>The maximum number of header bytes permitted per part in a request
    +      where the content type is <code>multipart/form-data</code>. Requests that
    +      exceed this limit will be rejected. A value of less than 0 means no limit.
    +      If not specified, a default of 512 is used.</p>
    +    </attribute>
    +
         <attribute name="maxPostSize" required="false">
           <p>The maximum size in bytes of the POST which will be handled by
           the container FORM URL parameter parsing. The limit can be disabled by
    

Vulnerability mechanics

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

References

11

News mentions

0

No linked articles in our index yet.