CVE-2026-3644
High · 7.5CVSS
7.5
EPSS
0.5%
Published
Mar 16, 2026
CISA due date
—
Cloudanix analysis
Some Python web applications may accidentally let attackers tamper with browser cookies if they build those cookies from unsafe user input.
- Exploitation
- Remote Authenticated
- Attacker needs
- Low Privilege
- Complexity
- Moderate
- Impact
- Data Tampering
- Component
- Library
- Class
- Improper Input Validation
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
This vulnerability is an incomplete input-validation fix in Python's standard-library http.cookies implementation. Control characters that were rejected in some http.cookies.Morsel paths can still be introduced through Morsel.update(), the Morsel union/update operator, and unpickling. BaseCookie.js_output() also lacks the output validation applied to BaseCookie.output(). If an application lets attacker-controlled data influence cookie names, values, or attributes through these paths, the library may emit malformed cookie output containing control characters such as carriage return or line feed. In practical terms, this can enable HTTP header injection, response-splitting behavior, cookie manipulation, or unsafe JavaScript cookie output depending on how the application uses the affected APIs.
Why it matters to the business
Applications using affected Python versions to generate cookies from user-influenced data may expose users to session manipulation, forced cookie changes, cache poisoning, or response tampering. The issue is not currently listed in CISA KEV, has low EPSS activity, and has no reported public exploit maturity, but it affects a widely used core language library, so exposure can be broad in Python-based web services and downstream frameworks that rely on http.cookies behavior.
How an attack unfolds
An attacker first needs to reach application functionality where cookie content or cookie attributes are derived from data they can influence, typically through an authenticated workflow, submitted profile data, preference values, redirect state, or another application parameter. The attacker supplies a crafted value containing control characters, most importantly CR/LF sequences, and relies on the application or a dependent library to place that value into a Morsel through one of the incompletely patched paths such as Morsel.update(), the |= operator, or deserialization of a Morsel-like object. When the application later serializes the cookie, especially through BaseCookie.js_output() or an affected output path, the control characters may be preserved rather than rejected. The resulting response can cause downstream clients, proxies, or browsers to interpret attacker-controlled content as additional headers, altered Set-Cookie directives, or unsafe script output. Successful exploitation depends on the application exposing one of these paths to attacker-influenced input and on how the emitted cookie output is consumed by clients or intermediaries.
How to fix it
Apply the Python security update from the operating-system, container-base-image, or language-runtime vendor once available for the affected Python release line. No exact fixed versions were provided in the input, so track the relevant Python advisory and vendor package channels for the complete fix to CVE-2026-3644. Where immediate upgrade is not possible, mitigate by ensuring application code never passes untrusted data directly into http.cookies.Morsel fields, Morsel.update(), cookie merge operations, unpickled cookie objects, or BaseCookie.js_output(). Reject or encode ASCII control characters in all cookie names, values, and attributes before they reach cookie-generation code. Avoid unpickling untrusted data entirely. Prefer framework cookie APIs that perform strict validation and output encoding, and add defensive tests that verify CR, LF, NUL, and other control characters are rejected in every cookie construction path.
How to confirm the fix worked
Confirm the runtime Python package has been updated to a vendor build containing the complete fix, not only the earlier CVE-2026-0672 fix. Inventory Python runtimes in hosts, containers, virtual environments, serverless functions, and packaged applications, then compare against the vendor advisory for the installed release line. Review code and dependency usage for http.cookies.Morsel.update(), Morsel |= operations, pickle.loads or pickle.load of cookie-related data, and BaseCookie.js_output(). Add regression tests that attempt to set cookie values and attributes containing \r, \n, \x00, and other control characters through Morsel.update(), union/update operators, unpickling if applicable, BaseCookie.output(), and BaseCookie.js_output(); the fixed or mitigated behavior should reject or safely encode those values and must not emit embedded control characters in response headers or script output. For running services, send safe test requests containing URL-encoded CR/LF sequences to non-production instances and verify no injected headers or malformed Set-Cookie output are returned.
Typical attack path
- Identify a Python-based web application or service that generates cookies using the standard-library http.cookies module.
- Find an input path where attacker-controlled data is incorporated into cookie names, values, attributes, or serialized cookie state.
- Submit a crafted value containing control characters such as carriage return and line feed, often encoded as %0d%0a or represented as raw CR/LF characters.
- Trigger application logic that updates a Morsel through Morsel.update(), the |= operator, unpickling, or a code path that later calls BaseCookie.js_output().
- Cause the application to emit a malformed Set-Cookie header or JavaScript cookie output containing the injected control characters.
- Abuse the interpreted response to manipulate cookies, inject additional headers, influence caching behavior, or tamper with client-side handling.
How to detect it
Look for evidence of attempted CR/LF or control-character injection into inputs that influence cookies. Relevant log sources include web server access logs, reverse-proxy logs, WAF events, application request logs, application error logs, HTTP response capture logs if available, and endpoint telemetry showing Python application behavior. Search requests for URL-encoded carriage return and line feed sequences in query strings, form bodies, JSON fields, Cookie headers, and parameters that are later used to set preferences, sessions, redirects, localization, theme settings, or other cookie-backed state. Review responses for anomalous Set-Cookie headers, multiple unexpected Set-Cookie headers, headers containing user-supplied values, or malformed response-header parsing by proxies. In code-aware telemetry, prioritize findings where suspicious requests coincide with use of http.cookies.Morsel.update(), BaseCookie.js_output(), cookie deserialization, or pickled cookie-like state. Also investigate downstream symptoms such as unexpected session changes, unusual cookie names, cache anomalies, or browser-side script errors following requests containing %0d or %0a. There are no known named threat actors, KEV activity, or public exploitation indicators provided, so detection should focus on behavior and malformed input/output artifacts rather than campaign-specific infrastructure.
- %0d%0aSet-Cookie:
- %0D%0ASet-Cookie:
- %0d%0aLocation:
- %0D%0ALocation:
- %0d%0aContent-Length:
- %0D%0AContent-Length:
- %0d%0aContent-Type:
- %0D%0AContent-Type:
- \r\nSet-Cookie:
- \r\nLocation:
- \r\nContent-Length:
- \r\nContent-Type:
- Morsel.update(
- BaseCookie.js_output(
- pickle.loads(
- pickle.load(
What your security team should do
- Prioritize inventory of externally exposed Python web applications and APIs that set cookies based on user-controlled input.
- Patch Python runtimes through official vendor channels as soon as fixed packages are available for the deployed release lines.
- Search application code for direct use of http.cookies, especially Morsel.update(), Morsel merge/update operators, BaseCookie.js_output(), and pickle handling of cookie-related objects.
- Add centralized validation that rejects all ASCII control characters in cookie names, values, and attributes before cookie serialization.
- Block or alert on requests containing CR/LF encodings in parameters commonly reflected into cookies, such as %0d, %0a, %0D, and %0A.
- Review WAF, reverse-proxy, and application logs for prior attempts to inject CR/LF sequences into cookie-related parameters or headers.
- Treat any untrusted pickle usage as a separate high-risk design issue and remove it where possible.
- Because EPSS is currently low, no KEV listing exists, and exploit maturity is reported as none, schedule remediation based on exposure: internet-facing and authentication/session-related services first.
The record
The fix for CVE-2026-0672, which rejected control characters in http.cookies.Morsel, was incomplete. The Morsel.update(), |= operator, and unpickling paths were not patched, allowing control characters to bypass input validation. Additionally, BaseCookie.js_output() lacked the output validation applied to BaseCookie.output().
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| Chainguard | python-3.13 | 0 | 3.13.12-r7 |
| Chainguard | python-3.14 | 0 | 3.14.3-r6 |
| SUSE:Linux Enterprise High Performance Computing 15 SP4-ESPOS | python310 | 0 | 3.10.20-150400.4.107.1 |
| SUSE:Linux Enterprise High Performance Computing 15 SP4-ESPOS | python310-core | 0 | 3.10.20-150400.4.107.1 |
| SUSE:Linux Enterprise High Performance Computing 15 SP4-LTSS | python310 | 0 | 3.10.20-150400.4.107.1 |
| SUSE:Linux Enterprise High Performance Computing 15 SP4-LTSS | python310-core | 0 | 3.10.20-150400.4.107.1 |
| SUSE:Linux Enterprise Module for Basesystem 15 SP7 | python311-core | 0 | 3.11.15-150600.3.53.1 |
| SUSE:Linux Enterprise Module for Package Hub 15 SP7 | python | 0 | 2.7.18-150000.111.1 |
| SUSE:Linux Enterprise Module for Package Hub 15 SP7 | python-base | 0 | 2.7.18-150000.111.1 |
| SUSE:Linux Enterprise Module for Python 3 15 SP7 | python311 | 0 | 3.11.15-150600.3.53.1 |
| SUSE:Linux Enterprise Module for Python 3 15 SP7 | python311-core | 0 | 3.11.15-150600.3.53.1 |
| SUSE:Linux Enterprise Server 15 SP4-LTSS | python310 | 0 | 3.10.20-150400.4.107.1 |
| SUSE:Linux Enterprise Server 15 SP4-LTSS | python310-core | 0 | 3.10.20-150400.4.107.1 |
| SUSE:Linux Enterprise Server 15 SP5-LTSS | python39 | 0 | 3.9.25-150300.4.99.1 |
| SUSE:Linux Enterprise Server 15 SP5-LTSS | python39-core | 0 | 3.9.25-150300.4.99.1 |
| SUSE:Linux Enterprise Server 15 SP6-LTSS | python311 | 0 | 3.11.15-150600.3.53.1 |
| SUSE:Linux Enterprise Server 15 SP6-LTSS | python311-core | 0 | 3.11.15-150600.3.53.1 |
| SUSE:Linux Enterprise Server 15 SP6-LTSS | python312 | 0 | 3.12.13-150600.3.53.1 |
| SUSE:Linux Enterprise Server 15 SP6-LTSS | python312-core | 0 | 3.12.13-150600.3.53.1 |
| SUSE:Linux Enterprise Server for SAP Applications 15 SP4 | python310 | 0 | 3.10.20-150400.4.107.1 |
| SUSE:Linux Enterprise Server for SAP Applications 15 SP4 | python310-core | 0 | 3.10.20-150400.4.107.1 |
| SUSE:Linux Enterprise Server for SAP Applications 15 SP5 | python39 | 0 | 3.9.25-150300.4.99.1 |
| SUSE:Linux Enterprise Server for SAP Applications 15 SP5 | python39-core | 0 | 3.9.25-150300.4.99.1 |
| SUSE:Linux Enterprise Server for SAP Applications 15 SP6 | python311 | 0 | 3.11.15-150600.3.53.1 |
| SUSE:Linux Enterprise Server for SAP Applications 15 SP6 | python311-core | 0 | 3.11.15-150600.3.53.1 |
| SUSE:Linux Enterprise Server for SAP Applications 15 SP6 | python312 | 0 | 3.12.13-150600.3.53.1 |
| SUSE:Linux Enterprise Server for SAP Applications 15 SP6 | python312-core | 0 | 3.12.13-150600.3.53.1 |
| Wolfi | python-3.13 | 0 | 3.13.12-r7 |
| Wolfi | python-3.14 | 0 | 3.14.3-r6 |
| openSUSE:Leap 15.6 | python | 0 | 2.7.18-150000.111.1 |
| openSUSE:Leap 15.6 | python-base | 0 | 2.7.18-150000.111.1 |
| openSUSE:Leap 15.6 | python-doc | 0 | 2.7.18-150000.111.1 |
| openSUSE:Leap 15.6 | python310 | 0 | 3.10.20-150400.4.107.1 |
| openSUSE:Leap 15.6 | python310-core | 0 | 3.10.20-150400.4.107.1 |
| openSUSE:Leap 15.6 | python310-documentation | 0 | 3.10.20-150400.4.107.1 |
| openSUSE:Leap 15.6 | python311 | 0 | 3.11.15-150600.3.53.1 |
| openSUSE:Leap 15.6 | python311-core | 0 | 3.11.15-150600.3.53.1 |
| openSUSE:Leap 15.6 | python311-documentation | 0 | 3.11.15-150600.3.53.1 |
| openSUSE:Leap 15.6 | python312 | 0 | 3.12.13-150600.3.53.1 |
| openSUSE:Leap 15.6 | python312-core | 0 | 3.12.13-150600.3.53.1 |
| openSUSE:Leap 15.6 | python312-documentation | 0 | 3.12.13-150600.3.53.1 |
| openSUSE:Leap 15.6 | python39 | 0 | 3.9.25-150300.4.99.1 |
| openSUSE:Leap 15.6 | python39-core | 0 | 3.9.25-150300.4.99.1 |
| openSUSE:Leap 15.6 | python39-documentation | 0 | 3.9.25-150300.4.99.1 |
| openSUSE:Leap 16.0 | python313 | 0 | 3.13.13-160000.1.1 |
| openSUSE:Leap 16.0 | python313-core | 0 | 3.13.13-160000.1.1 |
| openSUSE:Leap 16.0 | python313-documentation | 0 | 3.13.13-160000.1.1 |
| openSUSE:Leap 16.0 | python313-nogil | 0 | 3.13.13-160000.1.1 |
| openSUSE:Leap 16.0 | python313-nogil-nogil-core | 0 | 3.13.13-160000.1.1 |
| openSUSE:Tumbleweed | python310 | 0 | 3.10.20-3.1 |
| openSUSE:Tumbleweed | python311 | 0 | 3.11.15-4.1 |
| openSUSE:Tumbleweed | python312 | 0 | 3.12.13-4.1 |
| openSUSE:Tumbleweed | python313 | 0 | 3.13.12-3.1 |
| openSUSE:Tumbleweed | python314 | 0 | 3.14.3-4.1 |
| openSUSE:Tumbleweed | python315 | 0 | 3.15.0~a7-3.1 |
Related vulnerabilities
- CVE-2026-4519 The webbrowser.open() API would accept leading dashes in the URL which could be handled… Also affects python-3.13
- CVE-2026-4224 When an Expat parser with a registered ElementDeclHandler parses an inline document type… Also affects python-3.13
- CVE-2026-2297 The import hook in CPython that handles legacy *.pyc files (SourcelessFileLoader) is… Also affects python-3.13
- CVE-2026-1299 The email module, specifically the "BytesGenerator" class, didn’t properly quote newlines… Also affects python-3.13
- CVE-2026-0672 When using http.cookies.Morsel, user-controlled cookie values and parameters can allow… Also affects python-3.13
- CVE-2026-0865 User-controlled header names and values containing newlines can allow injecting HTTP… Also affects python-3.13
- CVE-2025-11468 When folding a long comment in an email header containing exclusively unfoldable… Also affects python-3.13
- CVE-2025-15282 User-controlled data URLs parsed by urllib.request.DataHandler allow injecting headers… Also affects python-3.13