Skip to content

chore(deps): [ai] Update vulnerabilityAlerts [SECURITY]#581

Open
renovate-bot wants to merge 1 commit into
GoogleCloudPlatform:mainfrom
renovate-bot:renovate/ai-vulnerabilityalerts
Open

chore(deps): [ai] Update vulnerabilityAlerts [SECURITY]#581
renovate-bot wants to merge 1 commit into
GoogleCloudPlatform:mainfrom
renovate-bot:renovate/ai-vulnerabilityalerts

Conversation

@renovate-bot

@renovate-bot renovate-bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
aiohttp ==3.13.4==3.14.1 age confidence
pydantic-settings (changelog) >=2.0.0>=2.14.2 age confidence
pydantic-settings (changelog) 2.14.12.14.2 age confidence
python-multipart (changelog) 0.0.270.0.31 age confidence
starlette (changelog) 1.0.11.3.1 age confidence
tornado (source) 6.5.56.5.7 age confidence

AIOHTTP is Vulnerable to Deserialization of Untrusted Data

CVE-2026-34993 / GHSA-jg22-mg44-37j8

More information

Details

Summary

Using CookieJar.load() with untrusted input may allow arbitrary code execution.

Impact

Most applications using this function will be doing so with the user's own data, so this is unlikely to affect many applications.

Workaround

If an application does allow attacker controlled files to be loaded, a workaround on older releases would be to sanitise the files before loading.


Patch: aio-libs/aiohttp@dcf40f3

Severity

  • CVSS Score: 6.4 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:C/C:L/I:H/A:L

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


AIOHTTP is vulnerable to cross-origin redirect with per-request cookies

CVE-2026-47265 / GHSA-hg6j-4rv6-33pg

More information

Details

Summary

Cookies set with the cookies parameter on requests are sent after following a cross-origin redirect.

Impact

If a developer uses the cookies parameter on a per-request basis then sensitive data might be leaked to an attacker if they manage to control a redirect.

Workaround

If unable to upgrade, using a Cookie header in the headers parameter is not vulnerable.


Patch: aio-libs/aiohttp@f54c408

Severity

  • CVSS Score: 6.6 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:U

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


AIOHTTP is vulnerable to cross-origin redirect with per-request cookies

CVE-2026-47265 / GHSA-hg6j-4rv6-33pg

More information

Details

Summary

Cookies set with the cookies parameter on requests are sent after following a cross-origin redirect.

Impact

If a developer uses the cookies parameter on a per-request basis then sensitive data might be leaked to an attacker if they manage to control a redirect.

Workaround

If unable to upgrade, using a Cookie header in the headers parameter is not vulnerable.


Patch: aio-libs/aiohttp@f54c408

Severity

  • CVSS Score: 6.6 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:U

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


AIOHTTP is Vulnerable to Deserialization of Untrusted Data

CVE-2026-34993 / GHSA-jg22-mg44-37j8

More information

Details

Summary

Using CookieJar.load() with untrusted input may allow arbitrary code execution.

Impact

Most applications using this function will be doing so with the user's own data, so this is unlikely to affect many applications.

Workaround

If an application does allow attacker controlled files to be loaded, a workaround on older releases would be to sanitise the files before loading.


Patch: aio-libs/aiohttp@dcf40f3

Severity

  • CVSS Score: 6.4 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:C/C:L/I:H/A:L

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


aiohttp: CRLF injection in multipart headers

CVE-2026-50269 / GHSA-m6qw-4cw2-hm4m

More information

Details

Summary

Attacker-controlled input included into multipart/payload headers can be used to modify a request to inject additional headers or similar.

Impact

In the unlikely situation that an application is passing user-controlled strings into MultipartWriter.append(headers=...) or Payload.headers, then an attacker may be able to modify the request to inject headers or change the contents of the request.

Workaround

Sanitise such user input.


Patch: aio-libs/aiohttp@bf88077

Severity

  • CVSS Score: 2.7 / 10 (Low)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:U

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


aiohttp: Host-Only Cookies Become Domain Cookies After CookieJar Persistence

CVE-2026-54279 / GHSA-2fqr-mr3j-6wp8

More information

Details

Summary

Host-only cookies that are saved with CookieJar.save() and then restored later with CookieJar.load() lose their host-only status.

Impact

Host-only cookies that have been loaded from disk may get sent to subdomains that previously should have been disallowed.


Patch: aio-libs/aiohttp@a329a7a

Severity

  • CVSS Score: 1.3 / 10 (Low)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:N/SA:N/E:U

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


aiohttp: HTTP/1 Pipelined Requests Queue Without Limit

CVE-2026-54273 / GHSA-4fvr-rgm6-gqmc

More information

Details

Summary

No limit was present on the number of pipelined requests that could be queued.

Impact

An attacker may be able to use pipelined requests to use excessive amounts of memory, potentially leading to DoS.


Patch: aio-libs/aiohttp@dfdfa9d

Severity

  • CVSS Score: 6.6 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:U

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


aiohttp: TLS Server Hostname Override Is Ignored When Reusing HTTPS Connections

CVE-2026-54275 / GHSA-4m7w-qmgq-4wj5

More information

Details

Summary

The server_hostname TLS SNI check can be bypassed when an existing connection is reused.

Impact

If an application makes multiple requests to the same domain, but with different per-request server_hostname parameters, then the later calls may succeed by reusing the existing connection when they should have been rejected due to the TLS SNI check.

Workaround

Disable keep_alive if you need to change the server_hostname check between requests.


Patch: aio-libs/aiohttp@0ca2b6c

Severity

  • CVSS Score: 2.7 / 10 (Low)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:U

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


aiohttp: C HTTP Parser Bypasses max_line_size for Fragmented Lines

CVE-2026-54277 / GHSA-63hw-fmq6-xxg2

More information

Details

Summary

It is possible to bypass the max_line_size check in parts of an HTTP request in the C parser.

Impact

If using the optimised C parser (the default in pre-built wheels), then an attacker may be able to send oversized lines through the HTTP parser and use an excessive amount of memory, potentially leading to DoS.


Patch: aio-libs/aiohttp@5ab61bb

Severity

  • CVSS Score: 6.6 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:U

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


aiohttp: Payload Response Resources Are Not Closed After Mid-Body Disconnect

CVE-2026-54280 / GHSA-9x8q-7h8h-wcw9

More information

Details

Summary

Payload resources are not closed correctly when a client disconnects in the middle of a write.

Impact

If a payload is using an open file or similar limited resource, then an attacker may be able to cause resource starvation temporarily until garbage collection or similar closes the file.


Patch: aio-libs/aiohttp@a762eda

Severity

  • CVSS Score: 1.7 / 10 (Low)
  • Vector String: CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:U

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


aiohttp: Unread Compressed Request Bodies Bypass client_max_size During Cleanup

CVE-2026-54278 / GHSA-g3cq-j2xw-wf74

More information

Details

Summary

During cleanup it is possible for a compressed request body to be decompressed into memory in one chunk.

Impact

An attacker may be able to send a compressed payload in specific situations that could be decompressed into memory, potentially leading to DoS (a zip bomb edge case).

Workaround

Disable compression if unable to upgrade.


Patch: aio-libs/aiohttp@4f7480e

Severity

  • CVSS Score: 6.6 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:U

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


aiohttp: DigestAuthMiddleware Applies Credentials to Cross-Origin Redirect Challenges

CVE-2026-54276 / GHSA-hpj7-wq8m-9hgp

More information

Details

Summary

DigestAuthMiddleware can send an authentication response after following a cross-origin redirect.

Impact

If the client follows a redirect (the default option) to an attacker controlled domain, the attacker may be able to extract the auth digest.

This likely requires an open redirect vulnerability or similar on the target domain for an attacker to be able to execute. Further, the attacker is only receiving the digest, so should only be able to extract the user's credentials if the cryptography is weak or there is some kind of password reuse.

Workaround

Disable follow_redirects if this is a concern.


Patch: aio-libs/aiohttp@38d1606

Severity

  • CVSS Score: 6.3 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


aiohttp: Incomplete websocket frame payloads bypass memory limits

CVE-2026-54274 / GHSA-xcgm-r5h9-7989

More information

Details

Summary

If an attacker sends large incomplete websocket frame payloads, it may be possible to bypass the usual size limits on memory use.

Impact

If a web application has WebSocket endpoints, it may be possible for an attacker to execute a DoS attack through excessive memory use.


Patch: aio-libs/aiohttp@14b6ee8

Severity

  • CVSS Score: 6.6 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:U

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


pydantic-settings: NestedSecretsSettingsSource follows symlinks outside secrets_dir, enabling local file read and bypassing secrets_dir_max_size

GHSA-4xgf-cpjx-pc3j

More information

Details

Summary

NestedSecretsSettingsSource reads secret values from files in a configured secrets_dir. When secrets_nested_subdir=True, a directory entry inside secrets_dir that is a symbolic link pointing outside secrets_dir is followed, so files outside the configured directory are read into settings values. The same code path bypasses the documented secrets_dir_max_size protection. An attacker or lower-privileged component able to influence entries in the configured secrets directory (for example, a writable or shared secrets mount) can turn this into an unintended local file read into settings and can defeat the advertised loading-size cap. This report does not claim network reachability by itself.

Details

NestedSecretsSettingsSource performed two passes over secrets_dir using two different, inconsistent directory-traversal implementations:

  • The size check in validate_secrets_path() used Path.glob('**/*'), which does not descend into a symbolically-linked directory.
  • The loader in load_secrets() used glob.iglob(f'{path}/**/*', recursive=True) followed by read_text(), which does follow symlinked directories and reads through the link target.

Because the two passes disagreed on symlinks, a symlinked directory inside secrets_dir whose target lives elsewhere was invisible to the size accounting (counted as 0 bytes) while still being fully read by the loader. This produces two distinct problems:

  1. Out-of-tree read (CWE-22 / CWE-59). A symlinked directory (or file) inside secrets_dir that resolves outside it is followed, and the external file's contents are loaded into the corresponding settings field.
  2. secrets_dir_max_size bypass (CWE-400). The size check never sees the out-of-tree content, so the documented size cap is neither respected nor able to reject the oversized external file. A related amplification exists for cyclic in-tree symlinks, which glob.iglob(recursive=True) re-traverses, inflating the size accounting and the number of loaded secrets.
Reproduction

In a clean Linux container, with a secrets_dir containing a symlink secrets/db -> /path/outside and an outside/passwd file of 512 bytes, while secrets_dir_max_size=100:

from pydantic import BaseModel
from pydantic_settings import (
    BaseSettings,
    SettingsConfigDict,
    NestedSecretsSettingsSource,
)

class Db(BaseModel):
    passwd: str | None = None

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        secrets_dir='secrets',
        secrets_nested_subdir=True,
        secrets_dir_max_size=100,  # outside/passwd is 512 bytes
    )
    db: Db = Db()

    @​classmethod
    def settings_customise_sources(
        cls, settings_cls, init_settings, env_settings, dotenv_settings, file_secret_settings
    ):
        return (NestedSecretsSettingsSource(file_secret_settings),)

On affected versions, Settings().db.passwd is populated with the 512-byte out-of-tree file and no SettingsError is raised, even though the file exceeds secrets_dir_max_size.

Impact

Applications that opt into NestedSecretsSettingsSource with secrets_nested_subdir=True and load secrets from a directory whose entries can be influenced by an attacker or a lower-privileged component (for example, a writable or shared secrets mount, or a secrets directory partially populated from untrusted input) are affected. The impact is:

  • Confidentiality: files outside the configured secrets_dir can be read into settings values (local file read).
  • Integrity / availability of the safeguard: the advertised secrets_dir_max_size cap can be bypassed, and cyclic symlinks can inflate resource usage during loading.

The vulnerability requires the ability to place a symbolic link inside the configured secrets directory; it is not remotely reachable on its own. Applications that do not use NestedSecretsSettingsSource, or that point secrets_dir at a directory fully under the application's control, are not affected.

Mitigation

Upgrade to pydantic-settings 2.14.2, which:

  • walks the secrets directory explicitly and only descends into directories whose resolved path stays within secrets_dir, so symlinked directories pointing outside are never followed;
  • uses a single, cycle-safe iterator for both the size check and the loader, so the size accounting and the loaded set are always consistent and each real directory is visited at most once;
  • skips any file whose resolved path escapes secrets_dir, as defense in depth.

If upgrading is not immediately possible, ensure the configured secrets_dir is fully owned and controlled by the application (no writable or attacker-influenced entries), or avoid secrets_nested_subdir=True.

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


python-multipart has Denial of Service via unbounded multipart part headers

CVE-2026-42561 / GHSA-pp6c-gr5w-3c5g

More information

Details

Summary

python-multipart has a denial of service vulnerability in multipart part header parsing. When parsing multipart/form-data, MultipartParser previously had no limit on the number of part headers or the size of an individual part header. An attacker could send a request with either many repeated headers without terminating the header block or a single very large header value, causing excessive CPU work before request rejection or completion.

Impact

Applications that parse attacker-controlled multipart/form-data with affected versions of python-multipart can experience CPU exhaustion. ASGI applications using Starlette, FastAPI, or other frameworks that invoke python-multipart may have worker or event-loop delays while processing malicious upload requests.

Details

The affected parser states are HEADER_FIELD_START, HEADER_FIELD, HEADER_VALUE_START, HEADER_VALUE, and HEADER_VALUE_ALMOST_DONE. The issue can be triggered by:

  • A multipart part with an oversized individual header value.
  • A multipart part with many repeated header lines or an unterminated header block.

Both variants are addressed by enforcing default parser limits for maximum header count and maximum header size.

Mitigation

Upgrade to python-multipart 0.0.27 or later.

If upgrading is not immediately possible, reduce exposure by enforcing request body size limits at the server, proxy, or framework layer. This is only a mitigation; affected versions of python-multipart still parse multipart part headers without the default header count and header size limits.

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


python-multipart: Content-Disposition parameter smuggling via RFC 2231/5987 extended parameters

CVE-2026-53537 / GHSA-vffw-93wf-4j4q

More information

Details

Summary

parse_options_header parsed Content-Disposition (and Content-Type) headers with email.message.Message, which transparently applies RFC 2231/5987 decoding. The extended parameter syntax (filename*=charset'lang'value, name*=..., and the filename*0/filename*1 continuation form) is decoded and surfaced under the bare filename/name key, and overrides the plain parameter when both are present. RFC 7578 §4.2 explicitly forbids the filename* form in multipart/form-data.

Components that follow RFC 7578, or that do not implement RFC 2231/5987 decoding for multipart/form-data (WAFs, proxies, gateways), may interpret such a header differently. An attacker can exploit that difference to smuggle a different field name or filename past an upstream inspector to the backend.

Details

Given both a plain and an extended parameter, the extended value won. For example:

Content-Disposition: form-data; name="comment"; name*=utf-8''role

An inspector following RFC 7578 sees the field comment, while the returned value was name=role. The same applies to filenames:

Content-Disposition: form-data; name="upload"; filename="safe.txt"; filename*=utf-8''evil.php

The inspector sees safe.txt, while the returned value was filename=evil.php. Continuation parameters (filename*0, filename*1, and so on) were likewise reassembled into a filename invisible to a plain filename= match, and percent encoded sequences in the extended value were decoded (so ..%2F, %00, and similar appeared in the returned filename).

This affects the high level parse_options_header, FormParser, create_form_parser, and parse_form APIs, and reaches Starlette/FastAPI through request.form(), where the smuggled value is exposed as the form field name or UploadFile.filename.

Impact

This is an interpretation conflict (CWE-436) with other multipart/form-data parsers. An attacker able to submit multipart/form-data can present a different field name or filename to an upstream body inspecting component than the one delivered to the application. Concrete consequences depend on how the application uses these values, and may include bypassing a field name or filename based access/upload control, or, for an application that builds filesystem paths from the parsed filename without sanitization, path traversal via decoded ..%2F sequences. Decoded control bytes such as %00 can likewise cause confusion between an upstream validator and the backend. The File class applies os.path.basename, so file writing through it is not directly affected.

Mitigation

Upgrade to python-multipart 0.0.30 or later, which ignores RFC 2231/5987 extended parameters (name*, filename*, and their continuations) so the plain name/filename parameter remains authoritative. RFC 7578 §4.2 forbids filename* for multipart/form-data; name* and the continuation forms are dropped for the same reason, since they are not valid multipart/form-data parameters either.

Severity

  • CVSS Score: 3.7 / 10 (Low)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


python-multipart: Semicolon treated as querystring field separator enables parameter smuggling

CVE-2026-53538 / GHSA-6jv3-5f52-599m

More information

Details

Summary

QuerystringParser treated ; as a field separator in application/x-www-form-urlencoded bodies, in addition to &. The WHATWG URL standard, modern browsers, and Python's urllib.parse (since the CVE-2021-23336 fix) treat only & as a separator. This creates a parser differential: the same bytes are tokenized into different fields than a WHATWG compliant intermediary would produce, allowing an attacker to smuggle extra form fields past an upstream body inspecting component.

Details

In python_multipart/multipart.py, the FIELD_NAME and FIELD_DATA states located the next separator by scanning for & and, failing that, for ;:

sep_pos = data.find(b"&", i)
if sep_pos == -1:
    sep_pos = data.find(b";", i)

As a result, ; acted as a field boundary. Because the fallback only triggered when no & remained in the current chunk, tokenization also depended on unrelated bytes later in the buffer and on how the body was split across write() calls. This is the same class of issue as CVE-2021-23336 in CPython's urllib.parse.

For example, a body inspecting WAF or gateway that follows the WHATWG rule (only & separates fields) receives:

role=user&x=;role=admin

The upstream parses two fields, role=user and x=";role=admin", sees a benign role=user, and forwards the request. QuerystringParser parsed the same bytes as three fields: role="user", x="", and role="admin". The application (for example via Starlette/FastAPI request.form(), where the last value wins) then received role=admin, a value the upstream validator never saw.

The parser is reachable through the public QuerystringParser class, the high level FormParser, create_form_parser, and parse_form APIs, and Starlette/FastAPI request.form() for url encoded bodies.

Impact

Interpretation conflict / HTTP parameter pollution. An attacker can smuggle extra or overriding form fields past an upstream component that applies the WHATWG separator rule, reaching the backend with parameters the intermediary did not observe.

Mitigation

Upgrade to python-multipart 0.0.30 or later, which treats only & as a field separator per the WHATWG URL standard. ; is parsed as ordinary field data, matching urllib.parse, browsers, and other compliant parsers.

Severity

  • CVSS Score: 3.7 / 10 (Low)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


python-multipart: Negative Content-Length in parse_form buffers the entire body in memory

CVE-2026-53540 / GHSA-v9pg-7xvm-68hf

More information

Details

Summary

parse_form() did not validate the Content-Length header before using it to bound its chunked read of the request body. A negative Content-Length turned the bounded read into a read-until-EOF, so the entire body was loaded into memory in a single read instead of in fixed-size chunks.

Details

parse_form() reads the input stream in chunks, never reading more than the remaining Content-Length at a time. The per-chunk size is computed as min(content_length - bytes_read, chunk_size). The header value was parsed to an integer without checking its sign, so a Content-Length of -1 made this expression negative, and input_stream.read(-1) reads until end of stream. The intended bounded, chunked read therefore collapsed into a single unbounded read of the whole stream. The amount read is still bounded by what the client actually sends.

Impact

This only affects code that calls parse_form() directly with a Content-Length header taken from attacker-controlled input and without normalizing a negative value first. No known package is affected:

  • Starlette and FastAPI drive MultipartParser directly from the ASGI receive() stream and do not call parse_form().
  • Known parse_form() consumers either do not forward Content-Length to it, recompute it from the already-read body, or run behind a layer (such as Werkzeug) that normalizes a negative Content-Length to 0.

The realistic exposure is limited to bespoke WSGI or http.server handlers that forward raw client headers into parse_form(). In that case a crafted request buffers the body in memory at once, degrading availability under concurrent requests rather than causing a complete denial of service.

Mitigation

Upgrade to version 0.0.31 or later, which rejects a negative Content-Length with a ValueError before reading the stream.

Severity

  • CVSS Score: 3.7 / 10 (Low)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


python-multipart: Quadratic-time querystring parsing with semicolon separators causes CPU denial of service

CVE-2026-53539 / GHSA-5rvq-cxj2-64vf

More information

Details

Summary

When parsing application/x-www-form-urlencoded bodies, QuerystringParser located the field separator with a two step lookup: it first scanned the entire remaining buffer for &, and only when no & existed anywhere ahead did it fall back to scanning for ;. For a body that uses ; as the separator and contains no &, every field iteration performed a full failed & scan over the entire remaining buffer before locating the nearby ;. With N semicolon separated fields in a chunk of size B, this yields O(B^2) byte comparisons per chunk.

An attacker can submit a small crafted body of the form a;a;a;... and cause the parser to spend seconds of CPU per request. A handful of concurrent requests can exhaust worker processes.

Details

In python_multipart/multipart.py, both the FIELD_NAME and FIELD_DATA states located the next separator like this:

sep_pos = data.find(b"&", i)
if sep_pos == -1:
    sep_pos = data.find(b";", i)

data.find(b"&", i) scans from i to the end of the buffer and returns -1 only when there is no & anywhere in the remainder. For a ; separated body with no &, this failed full buffer scan repeats once per field, making parsing quadratic in the body length.

For example, a 1 MiB url encoded body consisting of a; repeated ~500,000 times, submitted with Content-Type: application/x-www-form-urlencoded, causes the parser to perform on the order of 10^11 byte comparisons, consuming several seconds of CPU for a single request. Cost scales quadratically with chunk size.

The parser is reachable through the public QuerystringParser class and through the high level FormParser, create_form_parser, and parse_form APIs for url encoded bodies. It is also the parser Starlette and FastAPI use for application/x-www-form-urlencoded request bodies via request.form().

Impact

Uncontrolled CPU consumption (denial of service). Parsing is synchronous, so a single small crafted form body occupies the handling worker for seconds, blocking any other work on that worker until parsing finishes. Sustained concurrent requests keep workers continuously busy, degrading or denying service.

Mitigation

Upgrade to python-multipart 0.0.30 or later, which treats only & as a field separator (per the WHATWG URL standard) using a single bounded scan, making parsing linear in the body length.

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


python-multipart: Quadratic-time querystring parsing with semicolon separators causes CPU denial of service

CVE-2026-53539 / GHSA-5rvq-cxj2-64vf

More information

Details

Summary

When parsing application/x-www-form-urlencoded bodies, QuerystringParser located the field separator with a two step lookup: it first scanned the entire remaining buffer for &, and only when no & existed anywhere ahead did it fall back to scanning for ;. For a body that uses ; as the separator and contains no &, every field iteration performed a full failed & scan over the entire remaining buffer before locating the nearby ;. With N semicolon separated fields in a chunk of size B, this yields O(B^2) byte comparisons per chunk.

An attacker can submit a small crafted body of the form a;a;a;... and cause the parser to spend seconds of CPU per request. A handful of concurrent requests can exhaust worker processes.

Details

In python_multipart/multipart.py, both the FIELD_NAME and FIELD_DATA states located the next separator like this:

sep_pos = data.find(b"&", i)
if sep_pos == -1:
    sep_pos = data.find(b";", i)

data.find(b"&", i) scans from i to the end of the buffer and returns -1 only when there is no & anywhere in the remainder. For a ; separated body with no &, this failed full buffer scan repeats once per field, making parsing quadratic in the body length.

For example, a 1 MiB url encoded body consisting of a; repeated ~500,000 times, submitted with Content-Type: application/x-www-form-urlencoded, causes the parser to perform on the order of 10^11 byte comparisons, consuming several seconds of CPU for a single request. Cost scales quadratically with chunk size.

The parser is reachable through the public QuerystringParser class and through the high level FormParser, create_form_parser, and parse_form APIs for url encoded bodies. It is also the parser Starlette and FastAPI use for application/x-www-form-urlencoded request bodies via request.form().

Impact

Uncontrolled CPU consumption (denial of service). Parsing is synchronous, so a single small crafted form body occupies the handling worker for seconds, blocking any other work on that worker until parsing finishes. Sustained concurrent requests keep workers continuously busy, degrading or denying service.

Mitigation

Upgrade to python-multipart 0.0.30 or later, which treats only & as a field separator (per the WHATWG URL standard) using a single bounded scan, making parsing linear in the body length.

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


python-multipart: Semicolon treated as querystring field separator enables parameter smuggling

CVE-2026-53538 / GHSA-6jv3-5f52-599m

More information

Details

Summary

QuerystringParser treated ; as a field separator in application/x-www-form-urlencoded bodies, in addition to &. The WHATWG URL standard, modern browsers, and Python's urllib.parse (since the CVE-2021-23336 fix) treat only & as a separator. This creates a parser differential: the same bytes are tokenized into different fields than a WHATWG compliant intermediary would produce, allowing an attacker to smuggle extra form fields past an upstream body inspecting component.

Details

In python_multipart/multipart.py, the FIELD_NAME and FIELD_DATA states located the next separator by scanning for & and, failing that, for ;:

sep_pos = data.find(b"&", i)
if sep_pos == -1:
    sep_pos = data.find(b";", i)

As a result, ; acted as a field boundary. Because the fallback only triggered when no & remained in the current chunk, tokenization also depended on unrelated bytes later in the buffer and on how the body was split across write() calls. This is the same class of issue as CVE-2021-23336 in CPython's urllib.parse.

For example, a body inspecting WAF or gateway that follows the WHATWG rule (only & separates fields) receives:

role=user&x=;role=admin

The upstream parses two fields, role=user and x=";role=admin", sees a benign role=user, and forwards the request. QuerystringParser parsed the same bytes as three fields: role="user", x="", and role="admin". The application (for example via Starlette/FastAPI request.form(), where the last value wins) then received role=admin, a value the upstream validator never saw.

The parser is reachable through the public QuerystringParser class, the high level FormParser, create_form_parser, and parse_form APIs, and Starlette/FastAPI request.form() for url encoded bodies.

Impact

Interpretation conflict / HTTP parameter pollution. An attacker can smuggle extra or overriding form fields past an upstream component that applies the WHATWG separator rule, reaching the backend with parameters the intermediary did not observe.

Mitigation

Upgrade to python-multipart 0.0.30 or later, which treats only & as a field separator per the WHATWG URL standard. ; is parsed as ordinary field data, matching urllib.parse, browsers, and other compliant parsers.

Severity

  • CVSS Score: 3.7 / 10 (Low)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


python-multipart: Content-Disposition parameter smuggling via RFC 2231/5987 extended parameters

CVE-2026-53537 / GHSA-vffw-93wf-4j4q

More information

Details

Summary

parse_options_header parsed Content-Disposition (and Content-Type) headers with email.message.Message, which transparently applies RFC 2231/5987 decoding. The extended parameter syntax (filename*=charset'lang'value, name*=..., and the filename*0/filename*1 continuation form) is decoded and surfaced under the bare filename/name key, and overrides the plain parameter when both are present. RFC 7578 §4.2 explicitly forbids the filename* form in multipart/form-data.

Components that follow RFC 7578, or that do not implement RFC 2231/5987 decoding for multipart/form-data (WAFs, proxies, gateways), may interpret such a header differently. An attacker can exploit that difference to smuggle a different field name or filename past an upstream inspector to the backend.

Details

Given both a plain and an extended parameter, the extended value won. For example:

Content-Disposition: form-data; name="comment"; name*=utf-8''role

An inspector following RFC 7578 sees the field comment, while the returned value was name=role. The same applies to filenames:

Content-Disposition: form-data; name="upload"; filename="safe.txt"; filename*=utf-8''evil.php

The inspector sees safe.txt, while the returned value was filename=evil.php. Continuation parameters (filename*0, filename*1, and so on) were likewise reassembled into a filename invisible to a plain filename= match, and percent encoded sequences in the extended value were decoded (so ..%2F, %00, and similar appeared in the returned filename).

This affects the high level parse_options_header, FormParser, create_form_parser, and parse_form APIs, and reaches Starlette/FastAPI through request.form(), where the smuggled value is exposed as the form field name or UploadFile.filename.

Impact

This is an interpretation conflict (CWE-436) with other multipart/form-data parsers. An attacker able to submit multipart/form-data can present a different field name or filename to an upstream body inspecting component than the one delivered to the application. Concrete consequences depend on how the application uses these values, and may include bypassing a field name or filename based access/upload control, or, for an application that builds filesystem paths from the parsed filename without sanitization, path traversal via decoded ..%2F sequences. Decoded control bytes such as %00 can likewise cause confusion between an upstream validator and the backend. The File class applies os.path.basename, so file writing through it is not directly affected.

Mitigation

Upgrade to python-multipart 0.0.30 or later, which ignores RFC 2231/5987 extended parameters (name*, filename*, and their continuations) so the plain name/filename parameter remains authoritative. RFC 7578 §4.2 forbids filename* for multipart/form-data; name* and the continuation forms are dropped for the same reason, since they are not valid multipart/form-data parameters either.

Severity

  • CVSS Score: 3.7 / 10 (Low)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


python-multipart: Negative Content-Length in parse_form buffers the entire body in memory

CVE-2026-53540 / GHSA-v9pg-7xvm-68hf

More information

Details

Summary

parse_form() did not validate the Content-Length header before using it to bound its chunked read of the request body. A negative Content-Length turned the bounded read into a read-until-EOF, so the entire body was loaded into memory in a single read instead of in fixed-size chunks.

Details

parse_form() reads the input stream in chunks, never reading more than the remaining Content-Length at a time. The per-chunk size is computed as min(content_length - bytes_read, chunk_size). The header value was parsed to an integer without checking its sign, so a Content-Length of -1 made this expression negative, and input_stream.read(-1) reads until end of stream. The intended bounded, chunked read therefore collapsed into a single

Note

PR body was truncated to here.

@forking-renovate forking-renovate Bot added dependencies Pull requests that update a dependency file p0 SECURITY labels May 22, 2026
@renovate-bot renovate-bot force-pushed the renovate/ai-vulnerabilityalerts branch from d6207b7 to fc0b42f Compare May 31, 2026 03:40
@renovate-bot renovate-bot changed the title chore(deps): [ai] Update dependency idna to v3.16 [SECURITY] chore(deps): [ai] Update vulnerabilityAlerts to v3.16 [SECURITY] Jun 3, 2026
@renovate-bot renovate-bot force-pushed the renovate/ai-vulnerabilityalerts branch 4 times, most recently from 089f743 to 08eca96 Compare June 4, 2026 00:35
@renovate-bot renovate-bot changed the title chore(deps): [ai] Update vulnerabilityAlerts to v3.16 [SECURITY] chore(deps): [ai] Update vulnerabilityAlerts [SECURITY] Jun 4, 2026
@renovate-bot renovate-bot force-pushed the renovate/ai-vulnerabilityalerts branch 7 times, most recently from a063027 to 6f0bc7e Compare June 9, 2026 10:01
@renovate-bot renovate-bot force-pushed the renovate/ai-vulnerabilityalerts branch from 6f0bc7e to 7709c58 Compare June 13, 2026 20:15

@LUJ20 LUJ20 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM

@renovate-bot renovate-bot force-pushed the renovate/ai-vulnerabilityalerts branch 6 times, most recently from 3ad6515 to 575ed13 Compare June 19, 2026 16:49
@renovate-bot renovate-bot force-pushed the renovate/ai-vulnerabilityalerts branch from 575ed13 to 8079c05 Compare June 20, 2026 01:14
@renovate-bot renovate-bot force-pushed the renovate/ai-vulnerabilityalerts branch from 8079c05 to 7a80a19 Compare June 22, 2026 20:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file p0 SECURITY

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants