Fix CookieError crash with control characters on CPython builds with CVE-2026-3644 patch - #12395
Conversation
for more information, see https://pre-commit.ci
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #12395 +/- ##
=======================================
Coverage 98.94% 98.94%
=======================================
Files 131 131
Lines 46558 46610 +52
Branches 2409 2412 +3
=======================================
+ Hits 46068 46120 +52
Misses 367 367
Partials 123 123
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Merging this PR will improve performance by 8.47%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ⚡ | test_read_large_binary_websocket_messages |
48.9 µs | 45.1 µs | +8.47% |
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing rodrigobnogueira:fix-cookie-ctl-chars (d4dba3f) with master (65b42bb)2
Footnotes
-
69 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
-
No successful run was found on
master(302511f) during the generation of this report, so 65b42bb was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩
|
Tested with Python 3.13.3 and control chars seem to be accepted. Version might need to be narrowed in the summary |
|
looks like something like |
I think you mean removed. I could see no reason that CTL characters were supposed to be allowed, the test was a generic test of octal unquoting. So my assumption is that the tests arbitrarily chose CTL characters and they were not a deliberate choice, nor did it suggest real cookies would have such characters. It seems fine to me for them to be rejected as a security concern. |
…back - _safe_set_morsel_state now returns bool; callers skip unsalvageable cookies - Handles both octal-decoded CTL chars and literal CTL chars in raw headers - Added tests for literal control character edge case (bdraco feedback) - Updated version wording to reference CVE-2026-3644 patch, not Python 3.13+ - Reworded test docstrings per Dreamsorcerer feedback
for more information, see https://pre-commit.ci
Hello @Dreamsorcerer , the tests now describe what they actually verify (graceful handling vs crashing) without implying CTL chars should be allowed. |
- Add 'unsalvageable' to docs spelling wordlist (fixes linter) - Add test_parse_cookie_header_literal_ctl_chars for Cookie header path - Remove artificial test_preserve_morsel_with_coded_value_literal_ctl_chars (a Morsel with control chars can't be constructed through normal APIs)
2b9987b to
5e12a69
Compare
d34ac62 to
78d8173
Compare
for more information, see https://pre-commit.ci
|
I added a few extra tests to fix the missing coverage reported by Codecov. |
|
Pin pyupgrade to python3.13 to work around a crash introduced in Python 3.14 alpha (tokenize.cookie_re was changed from a string to a bytes pattern in 3.14, causing pyupgrade to fail with TypeError: cannot use a bytes pattern on a string-like object when run under 3.14). This is a pyupgrade bug |
|
Wow, looks like pyupgrade still targets the Python 3.7 syntax. cc @Dreamsorcerer do we still need it that low? Would it make sense to bump the tool's version in a standalone PR? |
|
@rodrigobnogueira I haven't found any pyupgrade issue filed upstream? I recommend creating it there and linking from the commit or at least anywhere so it'd be clearer what problem you're referring to. If you can — it'd be a good idea to submit a fix upstream. |
webknjaz
left a comment
There was a problem hiding this comment.
Below are a few notes/suggestions, not a full review.
I'm going to replace the whole setup with ruff in the near future, so haven't really looked at it. I did a manual upgrade with ruff a couple of months ago, though I only applied the safe fixes at that time, so still a few outdated bits in the code currently. |
Yeah, I saw that. That's just because those tests are outdated, right? We can backport the change to 3.13 branch to resolve that. |
|
861e965 to
d171cbd
Compare
- Use :cve:`2026-3644` and :external+python:exc: roles in changelog - Add pytest IDs to CTL chars from octal parametrize - Parametrize literal CTL char test (was two separate tests) - Use any() instead of list + in for semantic clarity - Replace unittest.mock.patch with monkeypatch fixture (no new dep) - Use @pytest.mark.usefixtures for void fixture injection - Remove pyupgrade language_version: python3.13 pin
d171cbd to
9317e23
Compare
Drop _safe_set_morsel_state helper and inline the try/except at each call site, as suggested by Dreamsorcerer — the function was simplified to a trivial wrapper and no longer warrants its own definition.
|
The new tests pass but don't the existing octal tests still expect decoding while they should be skipped now if This is on Python 3.13.13 and applied this PR to aiohttp 3.13.5. |
Thanks for testing! The failures are because you applied the PR to the released 3.13.5, but the test cases with control-char octals (\012, \011) were already replaced with printable-only octals on master in #12350, which has been backported to the 3.13 (#12401) and 3.14 (#12351) branches but not released yet. When this PR is backported it will land on those branches where the conflict is already resolved. |
Co-authored-by: Sam Bull <aa6bs0@sambull.org>
Backport to 3.14: 💚 backport PR created✅ Backport PR branch: Backported as #12533 🤖 @patchback |
…l characters on CPython builds with CVE-2026-3644 patch (#12533) **This is a backport of PR #12395 as merged into master (7eb0e80).** Co-authored-by: Rodrigo Nogueira <rodrigo.b.nogueira@gmail.com>
What do these changes do?
CPython builds that include the CVE-2026-3644 patch add strict validation to
Morsel.__setstate__that rejects values containing ASCII control characters. This causes aiohttp's cookie parser to crash withCookieErrorin two scenarios:_unquotedecodes sequences like\012to literal\n, which__setstate__then rejects.\x07(BEL) is unsalvageable since both the decoded value and thecoded_valuecontain the control character.This PR adds a
_safe_set_morsel_statehelper that:__setstate__and catchesCookieErrorFalseso callers gracefully skip the unsalvageable cookie instead of crashingAre there changes in behavior for the user?
Yes. On CPython builds with the CVE-2026-3644 patch, when a server sends a cookie containing a control character:
\012): the cookie is silently skipped\x07): the cookie is silently skippedIn both cases the parser no longer crashes. On CPython builds without the patch, behavior is unchanged.
Is it a substantial burden for the maintainers to support this?
No. The helper is a thin wrapper around the existing
__setstate__calls, uses the same patterns already established in the codebase, and is well-tested across both patched and unpatched CPython builds.Related issue number
N/A — This addresses a crash introduced by CPython's CVE-2026-3644 security patch.
Checklist
CONTRIBUTORS.txtCHANGES/folder