Skip to content

fix: reject requests with both Transfer-Encoding and Content-Length headers#1490

Merged
YangruiEmma merged 12 commits intocloudwego:mainfrom
YangruiEmma:fix/http-request-smuggling
Apr 2, 2026
Merged

fix: reject requests with both Transfer-Encoding and Content-Length headers#1490
YangruiEmma merged 12 commits intocloudwego:mainfrom
YangruiEmma:fix/http-request-smuggling

Conversation

@YangruiEmma
Copy link
Copy Markdown
Member

@YangruiEmma YangruiEmma commented Mar 31, 2026

Summary

Hardens HTTP/1.1 request header parsing to prevent HTTP request smuggling attacks. Aligned with RFC 9112 and Go net/http / nginx behavior.

Breaking Change: previously accepted requests may now be rejected with 400.

What changed

1. Reject Transfer-Encoding + Content-Length co-existence (RFC 9112 §6.3 Rule 3)

Rejects requests containing both headers in any order, returning errBothTEAndCL. Unlike Go net/http (which silently strips CL), we reject outright — this prevents CL.TE smuggling even when a front proxy doesn't understand TE.

2. Only accept Transfer-Encoding: chunked (like Go net/http and nginx)

  • Transfer-Encoding: identityrejected (removed in RFC 7230 / RFC 9112 §11.2; Go dropped support since 1.15)
  • Transfer-Encoding: gzip, chunkedrejected (multi-coding values are not used in practice but can cause proxy parsing inconsistencies)
  • Multiple Transfer-Encoding header lines → rejected with errMultipleTE (proxies merge multi-line headers inconsistently)
  • Only pure Transfer-Encoding: chunked (case-insensitive) is accepted

3. Reject duplicate Content-Length with conflicting values (RFC 9112 §6.3 Rule 5)

  • Content-Length: 10 + Content-Length: 20rejected with errDuplicateCL
  • Content-Length: 10 + Content-Length: 10 → accepted (identical values are safe)

Error types

Error Trigger
errBothTEAndCL TE + CL co-exist in any order
errDuplicateCL Multiple CL headers with different values
errUnsupportedTE TE value is not "chunked"
errMultipleTE More than one TE header line

Attack vectors mitigated

  • CL.TE smuggling: front proxy uses CL, backend uses TE → rejected at backend
  • TE.CL smuggling: front proxy uses TE, backend uses CL → rejected at backend
  • TE obfuscation: identity, gzip, chunked, multi-line TE, mixed-case tricks → all normalized or rejected

Comparison with Go net/http

Behavior Go net/http This PR
TE + CL co-exist Silent strip CL, accept Reject with 400 (more secure)
TE: identity Reject (since Go 1.15) Reject
TE: gzip, chunked Reject Reject
Multiple TE lines Reject Reject
Duplicate CL (same) Deduplicate Accept
Duplicate CL (diff) Reject Reject

@YangruiEmma YangruiEmma requested review from a team as code owners March 31, 2026 18:02
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 31, 2026

Codecov Report

❌ Patch coverage is 68.75000% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.10%. Comparing base (925126d) to head (edebfbf).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/protocol/http1/req/header.go 68.75% 1 Missing and 4 partials ⚠️

❌ Your patch status has failed because the patch coverage (68.75%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1490      +/-   ##
==========================================
- Coverage   86.25%   86.10%   -0.15%     
==========================================
  Files         148      148              
  Lines       14158    14172      +14     
==========================================
- Hits        12212    12203       -9     
+ Misses       1416     1410       -6     
- Partials      530      559      +29     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@YangruiEmma YangruiEmma merged commit 255b4a6 into cloudwego:main Apr 2, 2026
14 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants