VYPR
Moderate severityNVD Advisory· Published Jan 8, 2024· Updated Nov 3, 2025

HTTP Request/Response Smuggling in puma

CVE-2024-21647

Description

Puma is a web server for Ruby/Rack applications built for parallelism. Prior to version 6.4.2, puma exhibited incorrect behavior when parsing chunked transfer encoding bodies in a way that allowed HTTP request smuggling. Fixed versions limits the size of chunk extensions. Without this limit, an attacker could cause unbounded resource (CPU, network bandwidth) consumption. This vulnerability has been fixed in versions 6.4.2 and 5.6.8.

AI Insight

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

HTTP request smuggling vulnerability in Puma due to improper chunked transfer encoding parsing, allowing resource exhaustion; fixed in versions 6.4.2 and 5.6.8.

Puma, a popular Ruby web server, is vulnerable to HTTP request smuggling caused by incorrect parsing of chunked transfer encoding bodies [1]. The root issue is that prior to versions 6.4.2 and 5.6.8, Puma did not limit the size of chunk extensions in chunked requests [2]. This allows an attacker to send crafted chunked HTTP requests with excessively long extensions, leading to unbounded CPU and network bandwidth consumption [2].

An unauthenticated attacker can exploit this remotely by sending specially crafted chunked requests to a vulnerable Puma server [2]. The attack does not require any special privileges or network position, as it targets the parsing logic directly [1]. By sending a series of requests with large chunk extensions, the attacker can cause the server to consume resources indefinitely, potentially leading to denial of service [2].

The impact includes both resource exhaustion and HTTP request smuggling, which can enable further attacks such as cache poisoning, session hijacking, or bypassing security controls [2]. The vulnerability allows an attacker to manipulate how requests are interpreted, potentially leading to unintended behavior in downstream proxies or applications [1].

The vulnerability has been fixed by introducing two limits in the chunked body parser: a maximum chunk header size of 4096 bytes and a maximum cumulative excess of 16 KB for chunk extensions [3][4]. These limits prevent unbounded resource consumption by rejecting requests that exceed these thresholds. Administrators are advised to upgrade to Puma 6.4.2 or 5.6.8 immediately [2]. No workarounds are known.

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
pumaRubyGems
>= 6.0.0, < 6.4.26.4.2
pumaRubyGems
< 5.6.85.6.8

Affected products

13

Patches

3
60d5ee3734ad

Merge pull request from GHSA-c2f4-cvqm-65w2

https://github.com/puma/pumaNate BerkopecJan 8, 2024via ghsa
2 files changed · +41 0
  • lib/puma/client.rb+27 0 modified
    @@ -51,6 +51,14 @@ class Client # :nodoc:
         CHUNK_VALID_ENDING = Const::LINE_END
         CHUNK_VALID_ENDING_SIZE = CHUNK_VALID_ENDING.bytesize
     
    +    # The maximum number of bytes we'll buffer looking for a valid
    +    # chunk header.
    +    MAX_CHUNK_HEADER_SIZE = 4096
    +
    +    # The maximum amount of excess data the client sends
    +    # using chunk size extensions before we abort the connection.
    +    MAX_CHUNK_EXCESS = 16 * 1024
    +
         # Content-Length header value validation
         CONTENT_LENGTH_VALUE_INVALID = /[^\d]/.freeze
     
    @@ -496,6 +504,7 @@ def setup_chunked_body(body)
           @chunked_body = true
           @partial_part_left = 0
           @prev_chunk = ""
    +      @excess_cr = 0
     
           @body = Tempfile.new(Const::PUMA_TMP_BASE)
           @body.unlink
    @@ -577,6 +586,20 @@ def decode_chunk(chunk)
                 end
               end
     
    +          # Track the excess as a function of the size of the
    +          # header vs the size of the actual data. Excess can
    +          # go negative (and is expected to) when the body is
    +          # significant.
    +          # The additional of chunk_hex.size and 2 compensates
    +          # for a client sending 1 byte in a chunked body over
    +          # a long period of time, making sure that that client
    +          # isn't accidentally eventually punished.
    +          @excess_cr += (line.size - len - chunk_hex.size - 2)
    +
    +          if @excess_cr >= MAX_CHUNK_EXCESS
    +            raise HttpParserError, "Maximum chunk excess detected"
    +          end
    +
               len += 2
     
               part = io.read(len)
    @@ -604,6 +627,10 @@ def decode_chunk(chunk)
                 @partial_part_left = len - part.size
               end
             else
    +          if @prev_chunk.size + chunk.size >= MAX_CHUNK_HEADER_SIZE
    +            raise HttpParserError, "maximum size of chunk header exceeded"
    +          end
    +
               @prev_chunk = line
               return false
             end
    
  • test/test_puma_server.rb+14 0 modified
    @@ -904,6 +904,20 @@ def test_large_chunked_request
         end
       end
     
    +  def test_large_chunked_request_header
    +    server_run(environment: :production) { |env|
    +      [200, {}, [""]]
    +    }
    +
    +    max_chunk_header_size = Puma::Client::MAX_CHUNK_HEADER_SIZE
    +    header = "GET / HTTP/1.1\r\nConnection: close\r\nContent-Length: 200\r\nTransfer-Encoding: chunked\r\n\r\n"
    +    socket = send_http "#{header}1;t#{'x' * (max_chunk_header_size + 2)}"
    +
    +    data = socket.read
    +
    +    assert_match "HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n", data
    +  end
    +
       def test_chunked_request_pause_before_value
         body = nil
         content_length = nil
    
bbb880ffb6de

Merge pull request from GHSA-c2f4-cvqm-65w2

https://github.com/puma/pumaNate BerkopecJan 8, 2024via ghsa
2 files changed · +41 0
  • lib/puma/client.rb+27 0 modified
    @@ -48,6 +48,14 @@ class Client
         CHUNK_VALID_ENDING = Const::LINE_END
         CHUNK_VALID_ENDING_SIZE = CHUNK_VALID_ENDING.bytesize
     
    +    # The maximum number of bytes we'll buffer looking for a valid
    +    # chunk header.
    +    MAX_CHUNK_HEADER_SIZE = 4096
    +
    +    # The maximum amount of excess data the client sends
    +    # using chunk size extensions before we abort the connection.
    +    MAX_CHUNK_EXCESS = 16 * 1024
    +
         # Content-Length header value validation
         CONTENT_LENGTH_VALUE_INVALID = /[^\d]/.freeze
     
    @@ -460,6 +468,7 @@ def setup_chunked_body(body)
           @chunked_body = true
           @partial_part_left = 0
           @prev_chunk = ""
    +      @excess_cr = 0
     
           @body = Tempfile.new(Const::PUMA_TMP_BASE)
           @body.unlink
    @@ -541,6 +550,20 @@ def decode_chunk(chunk)
                 end
               end
     
    +          # Track the excess as a function of the size of the
    +          # header vs the size of the actual data. Excess can
    +          # go negative (and is expected to) when the body is
    +          # significant.
    +          # The additional of chunk_hex.size and 2 compensates
    +          # for a client sending 1 byte in a chunked body over
    +          # a long period of time, making sure that that client
    +          # isn't accidentally eventually punished.
    +          @excess_cr += (line.size - len - chunk_hex.size - 2)
    +
    +          if @excess_cr >= MAX_CHUNK_EXCESS
    +            raise HttpParserError, "Maximum chunk excess detected"
    +          end
    +
               len += 2
     
               part = io.read(len)
    @@ -568,6 +591,10 @@ def decode_chunk(chunk)
                 @partial_part_left = len - part.size
               end
             else
    +          if @prev_chunk.size + chunk.size >= MAX_CHUNK_HEADER_SIZE
    +            raise HttpParserError, "maximum size of chunk header exceeded"
    +          end
    +
               @prev_chunk = line
               return false
             end
    
  • test/test_puma_server.rb+14 0 modified
    @@ -648,6 +648,20 @@ def test_large_chunked_request
         end
       end
     
    +  def test_large_chunked_request_header
    +    server_run(environment: :production) { |env|
    +      [200, {}, [""]]
    +    }
    +
    +    max_chunk_header_size = Puma::Client::MAX_CHUNK_HEADER_SIZE
    +    header = "GET / HTTP/1.1\r\nConnection: close\r\nContent-Length: 200\r\nTransfer-Encoding: chunked\r\n\r\n"
    +    socket = send_http "#{header}1;t#{'x' * (max_chunk_header_size + 2)}"
    +
    +    data = socket.read
    +
    +    assert_match "HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n", data
    +  end
    +
       def test_chunked_request_pause_before_value
         body = nil
         content_length = nil
    
5fc43d73b6ff

5.6.8 and 6.4.2

https://github.com/puma/pumaNate BerkopecJan 8, 2024via ghsa
1 file changed · +10 0
  • History.md+10 0 modified
    @@ -1,3 +1,8 @@
    +## 6.4.2 / 2024-01-08
    +
    +* Security
    +  * Limit the size of chunk extensions. Without this limit, an attacker could cause unbounded resource (CPU, network bandwidth) consumption. ([GHSA-c2f4-cvqm-65w2](https://github.com/puma/puma/security/advisories/GHSA-c2f4-cvqm-65w2))
    +
     ## 6.4.1 / 2024-01-03
     
     * Bugfixes
    @@ -168,6 +173,11 @@
       * Ruby 3.2 will have native IO#wait_* methods, don't require io/wait ([#2903])
       * Various internal API refactorings ([#2942], [#2921], [#2922], [#2955])
     
    +## 5.6.8 / 2024-01-08
    +
    +* Security
    +  * Limit the size of chunk extensions. Without this limit, an attacker could cause unbounded resource (CPU, network bandwidth) consumption. ([GHSA-c2f4-cvqm-65w2](https://github.com/puma/puma/security/advisories/GHSA-c2f4-cvqm-65w2))
    +
     ## 5.6.7 / 2023-08-18
     
     * Security
    

Vulnerability mechanics

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

References

8

News mentions

0

No linked articles in our index yet.