Starlet 0.31 misreads chunked encoding, enabling request smuggling
TL;DR - Starlet through 0.31 picks Content-Length over Transfer-Encoding: chunked when both headers appear in the same request. RFC 7230 section 3.3.3 says the opposite. Behind a reverse proxy that follows the spec, that disagreement is a request smuggling primitive.
What happened
Starlet is a Perl PSGI/Plack HTTP server for running Perl web applications. CVE-2026-40561 is a header precedence bug classified as CWE-444 (Inconsistent Interpretation of HTTP Requests).
When a request carries both Content-Length and Transfer-Encoding: chunked, Starlet honours Content-Length. RFC 7230 section 3.3.3 is unambiguous: if Transfer-Encoding is present, it takes precedence and Content-Length must be ignored.
That gap is the attack surface. A front-end reverse proxy following the spec parses one request boundary; Starlet parses another. The desync lets an attacker smuggle a partial second request through the proxy - effectively prepending attacker-controlled data to the next legitimate request on the same connection.
| Item | Detail |
|---|---|
| Affected component | Starlet (Perl) |
| Affected versions | through 0.31 |
| Vulnerability class | HTTP Request Smuggling (header precedence) |
| CWE | CWE-444 |
This bug class recurs because HTTP parsing is underspecified in practice. Any time an intermediary and a backend implement slightly different rules for ambiguous requests, smuggling becomes possible. Next.js, Gunicorn, and various Java containers have all shipped variants of the same issue.
Who is impacted
- Services running
Starletat versions through0.31. - Deployments sitting behind a front-end reverse proxy - nginx, HAProxy, Caddy, a CDN edge - where the proxy and
Starletcan disagree on request boundaries. - Internet-facing endpoints that accept untrusted client traffic through the proxy layer. Internal-only services with no HTTP intermediary have no attack path.
What to do now
- Apply the fix. The CPAN Security Group advisory is clear:
"Migrate to Starman 0.4018 or later which has fixed this issue or apply the patch."
- Inventory your Perl services. Check deployed artifacts and container images for any path still running on
Starlet. Version pinning incpanfileorMakefile.PLis the fastest place to confirm what you're actually running. - If you operate a reverse proxy in front of Perl app servers, check whether it can be configured to reject or normalise requests that carry both
Content-LengthandTransfer-Encodingheaders. That removes the attack shape at the edge, independent of backend patching. - If you suspect prior exposure, query edge and application logs for requests that include both headers. Look for downstream anomalies consistent with request desync: unexpected
4xxspikes, mismatched request counts, or unusual keep-alive behaviour.
Related
Guides
Content is AI-assisted and reviewed by our team, but issues may be missed and best practices evolve rapidly, send corrections to [email protected]. Always consult official documentation and validate key implementation decisions before making design or security choices.
