Skip to content

fix: reject conflicting content-length headers#1317

Open
Harshal96 wants to merge 5 commits into
python-hyper:masterfrom
Harshal96:fix-duplicate-content-length-1316
Open

fix: reject conflicting content-length headers#1317
Harshal96 wants to merge 5 commits into
python-hyper:masterfrom
Harshal96:fix-duplicate-content-length-1316

Conversation

@Harshal96
Copy link
Copy Markdown
Contributor

Summary

  • Check all inbound content-length header fields before setting the expected body length
  • Reject duplicate content-length fields when their parsed decimal values differ
  • Add inbound tests for matching and conflicting duplicate fields

Fixes #1316

Tests

  • Added unit tests

Comment thread src/h2/stream.py Outdated
if n == b"content-length":
try:
self._expected_content_length = int(v, 10)
content_lengths.append(int(v, 10))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this lead to a DoS if a malicous payload keeps sending new differing content-length headers and this list keeps growing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I don't think so, it'll be discarded once _initialize_content_length() exits, but I think I have a better idea where only comparing the lengths can work as well, lemme push a fix

@Kriechi
Copy link
Copy Markdown
Member

Kriechi commented May 14, 2026

asking for a second opinion from @mhils:
how does mitmproxy deal with duplicate or conflicting content-length headers?
last-one-wins? first-one-wins? throw an error / close the connection?

@mhils
Copy link
Copy Markdown
Member

mhils commented May 15, 2026

how does mitmproxy deal with duplicate or conflicting content-length headers?

We reject them, because it has tremendous request smuggling potential.

Comment thread src/h2/stream.py Outdated
if content_length is None:
content_length = parsed_content_length
elif parsed_content_length != content_length:
msg = "Conflicting content-length headers"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add both values into the error message here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread src/h2/stream.py
if content_length is None:
return

self._expected_content_length = content_length
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be simplified here: if content_length is None, then just assign it anyway, as _expected_content_length is going to be also None.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@Kriechi
Copy link
Copy Markdown
Member

Kriechi commented May 18, 2026

@Harshal96 please add a changelog entry to document the new behaviour - this is breaking change, as the previous code paths silently accepted the first found content-length header (ignoring all others), while the new behaviour will raise a ProtocolError if there is a second header with a different value.

I am still considering if such a compliance check should better be part of the existing checks in utilities.py::validate_headers. What do you think?

@Harshal96
Copy link
Copy Markdown
Contributor Author

@Kriechi the check is tied to stream body accounting, so maybe should not be a part of validate_headers, but this is one of my initial contributions in this repo, so happy to accomodate the feedback if you feel it's better suited in validate_headers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reject conflicting duplicate Content-Length headers

3 participants