High severity7.5NVD Advisory· Published Apr 29, 2026· Updated May 6, 2026
CVE-2026-40560
CVE-2026-40560
Description
Starman versions before 0.4018 for Perl allows HTTP Request Smuggling via Improper Header Precedence.
Starman incorrectly prioritizes "Content-Length" over "Transfer-Encoding: chunked" when both headers are present in an HTTP request. Per RFC 7230 3.3.3, Transfer-Encoding must take precedence.
An attacker could exploit this to smuggle malicious HTTP requests via a front-end reverse proxy.
Affected products
2Patches
1ced205f08050Fix request smuggling (CVE-2026-40560): Transfer-Encoding takes precedence over Content-Length
3 files changed · +73 −14
Changes+2 −0 modified@@ -1,6 +1,8 @@ Revision history for Perl extension Starman {{$NEXT}} + - Fix HTTP request smuggling: Transfer-Encoding now takes precedence + over Content-Length per RFC 7230 §3.3.3 (CVE-2026-40560) 0.4017 2023-09-13 13:27:02 PDT - Handle EINTR when doing sysread calls (Rob Mueller) #148
lib/Starman/Server.pm+14 −14 modified@@ -415,20 +415,7 @@ sub _prepare_env { my $chunked = do { no warnings; lc delete $env->{HTTP_TRANSFER_ENCODING} eq 'chunked' }; - if (my $cl = $env->{CONTENT_LENGTH}) { - my $buf = Plack::TempBuffer->new($cl); - while ($cl > 0) { - my($chunk, $read) = $get_chunk->(); - - if ( !defined $read || $read == 0 ) { - die "Read error: $!\n"; - } - - $cl -= $read; - $buf->print($chunk); - } - $env->{'psgi.input'} = $buf->rewind; - } elsif ($chunked) { + if ($chunked) { my $buf = Plack::TempBuffer->new; my $chunk_buffer = ''; my $length; @@ -460,6 +447,19 @@ sub _prepare_env { $env->{CONTENT_LENGTH} = $length; $env->{'psgi.input'} = $buf->rewind; + } elsif (my $cl = $env->{CONTENT_LENGTH}) { + my $buf = Plack::TempBuffer->new($cl); + while ($cl > 0) { + my($chunk, $read) = $get_chunk->(); + + if ( !defined $read || $read == 0 ) { + die "Read error: $!\n"; + } + + $cl -= $read; + $buf->print($chunk); + } + $env->{'psgi.input'} = $buf->rewind; } else { $env->{'psgi.input'} = $null_io; }
t/te_cl_precedence.t+57 −0 added@@ -0,0 +1,57 @@ +use strict; +use warnings; +use Test::TCP; +use IO::Socket::INET qw/ SHUT_WR /; +use HTTP::Response; +use Plack::Loader; +use Test::More; + +# RFC 7230 §3.3.3: when both Transfer-Encoding and Content-Length are +# present, Transfer-Encoding must override Content-Length. +test_tcp( + client => sub { + my $port = shift; + + my $socket = IO::Socket::INET->new( + PeerAddr => 'localhost', + PeerPort => $port, + Proto => 'tcp', + ) or die "Failed to connect: $!"; + + # Chunked body encodes "Hello World" (0xb = 11 bytes). + # Content-Length: 5 is intentionally wrong — it must be ignored. + my $chunked_body = "b\r\nHello World\r\n0\r\n\r\n"; + my $req = "POST / HTTP/1.1\r\n" + . "Host: localhost\r\n" + . "Transfer-Encoding: chunked\r\n" + . "Content-Length: 5\r\n" + . "\r\n" + . $chunked_body; + + $socket->send($req); + $socket->shutdown(SHUT_WR); + + my $response = ''; + while (1) { + my $n = $socket->sysread(my $buf, 4096); + last unless $n; + $response .= $buf; + } + + my $res = HTTP::Response->parse($response); + is $res->content, 'Hello World', + 'Transfer-Encoding: chunked takes precedence over Content-Length'; + }, + server => sub { + my $port = shift; + my $server = Plack::Loader->load('Starman', port => $port, host => '127.0.0.1'); + $server->run(sub { + my $env = shift; + my $body = ''; + $env->{'psgi.input'}->read($body, 8192); + return [ 200, [ 'Content-Type', 'text/plain', 'Content-Length', length($body) ], [ $body ] ]; + }); + }, +); + +done_testing;
Vulnerability mechanics
AI mechanics synthesis has not run for this CVE yet.
References
4- github.com/miyagawa/Starman/commit/ced205f0805027e9d9c0731f8c40b104220604ed.patchnvdPatchThird Party Advisory
- www.openwall.com/lists/oss-security/2026/04/29/1nvdMailing ListThird Party Advisory
- datatracker.ietf.org/doc/html/rfc7230nvdThird Party Advisory
- metacpan.org/release/MIYAGAWA/Starman-0.4018/changesnvdProductRelease Notes
News mentions
0No linked articles in our index yet.