Skip to content

Conversation

renovate[bot]
Copy link
Contributor

@renovate renovate bot commented Dec 20, 2024

This PR contains the following updates:

Package Change Age Adoption Passing Confidence
starlette (changelog) ==0.37.2 -> ==0.47.2 age adoption passing confidence

GitHub Vulnerability Alerts

CVE-2024-47874

Summary

Starlette treats multipart/form-data parts without a filename as text form fields and buffers those in byte strings with no size limit. This allows an attacker to upload arbitrary large form fields and cause Starlette to both slow down significantly due to excessive memory allocations and copy operations, and also consume more and more memory until the server starts swapping and grinds to a halt, or the OS terminates the server process with an OOM error. Uploading multiple such requests in parallel may be enough to render a service practically unusable, even if reasonable request size limits are enforced by a reverse proxy in front of Starlette.

PoC

from starlette.applications import Starlette
from starlette.routing import Route

async def poc(request):
    async with request.form():
        pass

app = Starlette(routes=[
    Route('/', poc, methods=["POST"]),
])
curl http://localhost:8000 -F 'big=</dev/urandom'

Impact

This Denial of service (DoS) vulnerability affects all applications built with Starlette (or FastAPI) accepting form requests.

CVE-2025-54121

Summary

When parsing a multi-part form with large files (greater than the default max spool size) starlette will block the main thread to roll the file over to disk. This blocks the event thread which means we can't accept new connections.

Details

Please see this discussion for details: https://github.com/encode/starlette/discussions/2927#discussioncomment-13721403. In summary the following UploadFile code (copied from here) has a minor bug. Instead of just checking for self._in_memory we should also check if the additional bytes will cause a rollover.

    @&#8203;property
    def _in_memory(self) -> bool:
        # check for SpooledTemporaryFile._rolled
        rolled_to_disk = getattr(self.file, "_rolled", True)
        return not rolled_to_disk

    async def write(self, data: bytes) -> None:
        if self.size is not None:
            self.size += len(data)

        if self._in_memory:
            self.file.write(data)
        else:
            await run_in_threadpool(self.file.write, data)

I have already created a PR which fixes the problem: https://github.com/encode/starlette/pull/2962

PoC

See the discussion here for steps on how to reproduce.

Impact

To be honest, very low and not many users will be impacted. Parsing large forms is already CPU intensive so the additional IO block doesn't slow down starlette that much on systems with modern HDDs/SSDs. If someone is running on tape they might see a greater impact.


Starlette Denial of service (DoS) via multipart/form-data

CVE-2024-47874 / GHSA-f96h-pmfr-66vw

More information

Details

Summary

Starlette treats multipart/form-data parts without a filename as text form fields and buffers those in byte strings with no size limit. This allows an attacker to upload arbitrary large form fields and cause Starlette to both slow down significantly due to excessive memory allocations and copy operations, and also consume more and more memory until the server starts swapping and grinds to a halt, or the OS terminates the server process with an OOM error. Uploading multiple such requests in parallel may be enough to render a service practically unusable, even if reasonable request size limits are enforced by a reverse proxy in front of Starlette.

PoC
from starlette.applications import Starlette
from starlette.routing import Route

async def poc(request):
    async with request.form():
        pass

app = Starlette(routes=[
    Route('/', poc, methods=["POST"]),
])
curl http://localhost:8000 -F 'big=</dev/urandom'
Impact

This Denial of service (DoS) vulnerability affects all applications built with Starlette (or FastAPI) accepting form requests.

Severity

  • CVSS Score: 8.7 / 10 (High)
  • 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

References

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


Starlette has possible denial-of-service vector when parsing large files in multipart forms

CVE-2025-54121 / GHSA-2c2j-9gv5-cj73

More information

Details

Summary

When parsing a multi-part form with large files (greater than the default max spool size) starlette will block the main thread to roll the file over to disk. This blocks the event thread which means we can't accept new connections.

Details

Please see this discussion for details: https://github.com/encode/starlette/discussions/2927#discussioncomment-13721403. In summary the following UploadFile code (copied from here) has a minor bug. Instead of just checking for self._in_memory we should also check if the additional bytes will cause a rollover.

    @&#8203;property
    def _in_memory(self) -> bool:
        # check for SpooledTemporaryFile._rolled
        rolled_to_disk = getattr(self.file, "_rolled", True)
        return not rolled_to_disk

    async def write(self, data: bytes) -> None:
        if self.size is not None:
            self.size += len(data)

        if self._in_memory:
            self.file.write(data)
        else:
            await run_in_threadpool(self.file.write, data)

I have already created a PR which fixes the problem: https://github.com/encode/starlette/pull/2962

PoC

See the discussion here for steps on how to reproduce.

Impact

To be honest, very low and not many users will be impacted. Parsing large forms is already CPU intensive so the additional IO block doesn't slow down starlette that much on systems with modern HDDs/SSDs. If someone is running on tape they might see a greater impact.

Severity

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

References

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


Release Notes

Kludex/starlette (starlette)

v0.47.2

Compare Source

Fixed

  • Make UploadFile check for future rollover #​2962.

New Contributors

Full Changelog: Kludex/starlette@0.47.1...0.47.2

v0.47.1: Version 0.47.1

Compare Source

Fixed

  • Use Self in TestClient.__enter__ #​2951
  • Allow async exception handlers to type-check #​2949

Full Changelog: Kludex/starlette@0.47.0...0.47.1

v0.47.0: Version 0.47.0

Compare Source

Added

  • Add support for ASGI pathsend extension #​2671.
  • Add partitioned attribute to Response.set_cookie #​2501.

Changed

  • Change methods parameter type from list[str] to Collection[str] #​2903.
  • Replace import typing by from typing import ... in the whole codebase #​2867.

Fixed

  • Mark ExceptionMiddleware.http_exception as async to prevent thread creation #​2922.

New Contributors

Full Changelog: Kludex/starlette@0.46.2...0.47.0

v0.46.2: Version 0.46.2

Compare Source

What's Changed

New Contributors

Full Changelog: Kludex/starlette@0.46.1...0.46.2

v0.46.1: Version 0.46.1

Compare Source

Fixed

  • Allow relative directory path when follow_symlinks=True #​2896.

Full Changelog: Kludex/starlette@0.46.0...0.46.1

v0.46.0: Version 0.46.0

Compare Source

Added

  • GZipMiddleware: Make sure Vary header is always added if a response can be compressed #​2865.

Fixed

  • Raise exception from background task on BaseHTTPMiddleware #​2812.
  • GZipMiddleware: Don't compress on server sent events #​2871.

Changed

  • MultiPartParser: Rename max_file_size to spool_max_size #​2780.

Deprecated

  • Add deprecated warning to TestClient(timeout=...) #​2840.

New Contributors

Full Changelog: Kludex/starlette@0.45.3...0.46.0

v0.45.3: Version 0.45.3

Compare Source

Fixed


Full Changelog: Kludex/starlette@0.45.2...0.45.3

v0.45.2: Version 0.45.2

Compare Source

Fixed
  • Make create_memory_object_stream compatible with old anyio versions once again, and bump anyio minimum version to 3.6.2 by @​graingert in #​2833.

Full Changelog: Kludex/starlette@0.45.1...0.45.2

v0.45.1: Version 0.45.1

Compare Source

Fixed
Refactor

Full Changelog: Kludex/starlette@0.45.0...0.45.1

v0.45.0: Version 0.45.0

Compare Source

Removed


Full Changelog: Kludex/starlette@0.44.0...0.45.0

v0.44.0: Version 0.44.0

Compare Source

Added

New Contributors

Full Changelog: Kludex/starlette@0.43.0...0.44.0

v0.43.0: Version 0.43.0

Compare Source

Removed

  • Remove deprecated allow_redirects argument from TestClient #​2808.

Added

  • Make UUID path parameter conversion more flexible #​2806.

New Contributors

Full Changelog: Kludex/starlette@0.42.0...0.43.0

v0.42.0: Version 0.42.0

Compare Source

Added

  • Raise ClientDisconnect on StreamingResponse #​2732.

Fixed

  • Use ETag from headers when parsing If-Range in FileResponse #​2761.
  • Follow directory symlinks in StaticFiles when follow_symlinks=True #​2711.
  • Bump minimum python-multipart version to 0.0.18 0ba8395.
  • Bump minimum httpx version to 0.27.0 #​2773.

New Contributors

Full Changelog: Kludex/starlette@0.41.3...0.42.0

v0.41.3: Version 0.41.3

Compare Source

Fixed

  • Exclude the query parameters from the scope[raw_path] on the TestClient #​2716.
  • Replace dict by Mapping on HTTPException.headers #​2749.
  • Correct middleware argument passing and improve factory pattern #​2752.

Full Changelog: Kludex/starlette@0.41.2...0.41.3

v0.41.2: Version 0.41.2

Compare Source

What's Changed


Full Changelog: Kludex/starlette@0.41.1...0.41.2

v0.41.1: Version 0.41.1

Compare Source

What's Changed


Full Changelog: Kludex/starlette@0.41.0...0.41.1

v0.41.0: Version 0.41.0

Compare Source

Added

  • Allow to raise HTTPException before websocket.accept() encode#2725

v0.40.0: Version 0.40.0

Compare Source

This release fixes a Denial of service (DoS) via multipart/form-data requests.

You can view the full security advisory:
GHSA-f96h-pmfr-66vw

Fixed

  • Add max_part_size to MultiPartParser to limit the size of parts in multipart/form-data
    requests fd038f3.

v0.39.2: Version 0.39.2

Compare Source

Fixed

  • Allow use of request.url_for when only "app" scope is available #​2672.
  • Fix internal type hints to support python-multipart==0.0.12 #​2708.

Full Changelog: Kludex/starlette@0.39.1...0.39.2

v0.39.1: Version 0.39.1

Compare Source

Fixed
  • Avoid regex re-compilation in responses.py and schemas.py #​2700.
  • Improve performance of get_route_path by removing regular expression usage #​2701.
  • Consider FileResponse.chunk_size when handling multiple ranges #​2703.
  • Use token_hex for generating multipart boundary strings #​2702.

Full Changelog: Kludex/starlette@0.39.0...0.39.1

v0.39.0: Version 0.39.0

Compare Source

Added
  • Add support for HTTP Range to FileResponse #​2697

Full Changelog: Kludex/starlette@0.38.6...0.39.0

v0.38.6: Version 0.38.6

Compare Source

Fixed

  • Close unclosed MemoryObjectReceiveStream in TestClient #​2693.

Full Changelog: Kludex/starlette@0.38.5...0.38.6

v0.38.5: Version 0.38.5

Compare Source

Fixed

  • Schedule BackgroundTasks from within BaseHTTPMiddleware #​2688.
    This behavior was removed in 0.38.3, and is now restored.

Full Changelog: Kludex/starlette@0.38.4...0.38.5

v0.38.4: Version 0.38.4

Compare Source

Fixed

  • Ensure accurate root_path removal in get_route_path function #​2600

Full Changelog: Kludex/starlette@0.38.3...0.38.4

v0.38.3: Version 0.38.3

Compare Source

Added
Fixed
  • Don't poll for disconnects in BaseHTTPMiddleware via StreamingResponse #​2620.

Full Changelog: Kludex/starlette@0.38.2...0.38.3

v0.38.2: Version 0.38.2

Compare Source

Fixed

  • Fix routing.get_name() not to assume all routines have __name__ #​2648

Full Changelog: Kludex/starlette@0.38.1...0.38.2

v0.38.1: Version 0.38.1

Compare Source

Removed

  • Revert "Add support for ASGI pathsend extension" #​2649.

Full Changelog: Kludex/starlette@0.38.0...0.38.1

v0.38.0: Version 0.38.0

Compare Source

Added

  • Allow use of memoryview in StreamingResponse and Response #​2576
    and #​2577.
  • Send 404 instead of 500 when filename requested is too long on StaticFiles #​2583.

Changed

  • Fail fast on invalid Jinja2Template instantiation parameters #​2568.
  • Check endpoint handler is async only once #​2536.

Fixed

  • Add proper synchronization to WebSocketTestSession #​2597.

Full Changelog: Kludex/starlette@0.37.2...0.38.0


Configuration

📅 Schedule: Branch creation - "" in timezone America/Toronto, Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@thepetk thepetk mentioned this pull request Dec 21, 2024
2 tasks
@thepetk
Copy link
Contributor

thepetk commented Dec 21, 2024

Hold off merging because config.env needs to be added in the developer image (but this is optional).

My thoughts here:

  • In case the config.env is not present I think the best approach for renovate is to skip this PR.
  • In case the config.env is not present the validate images should exit with non-zero status blocking the merge of the PR.

cc @Jdubrick @maysunfaisal

Copy link
Contributor

@thepetk thepetk left a comment

Choose a reason for hiding this comment

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

See comment here: #22 (comment)

@thepetk
Copy link
Contributor

thepetk commented Dec 21, 2024

See comment here: #22 (comment)

created label do-not-merge/hold and assigned it. I think we could also disable merge when changes are requested.

@thepetk
Copy link
Contributor

thepetk commented Dec 21, 2024

Similar status has seen on other PRs
#21
#20
#19
#18

Might be a good idea to group those updates so we can have less PRs generated from renovate? IIRC we can even do it for only patch/minor updates without risking combining a major update with minor/patch.

cc @Jdubrick

@Jdubrick
Copy link
Contributor

Jdubrick commented Jan 6, 2025

Similar status has seen on other PRs #21 #20 #19 #18

Might be a good idea to group those updates so we can have less PRs generated from renovate? IIRC we can even do it for only patch/minor updates without risking combining a major update with minor/patch.

cc @Jdubrick

Agreed on your comment regarding the config.env, if we have other suggestions for handling the gh action push without needing to maintain a file like that I am open to hearing suggestions as well.

I can look into the grouping of the PRs this week since I am now back from PTO @thepetk

@thepetk
Copy link
Contributor

thepetk commented Jan 6, 2025

Similar status has seen on other PRs #21 #20 #19 #18
Might be a good idea to group those updates so we can have less PRs generated from renovate? IIRC we can even do it for only patch/minor updates without risking combining a major update with minor/patch.
cc @Jdubrick

Agreed on your comment regarding the config.env, if we have other suggestions for handling the gh action push without needing to maintain a file like that I am open to hearing suggestions as well.

I can look into the grouping of the PRs this week since I am now back from PTO @thepetk

Ideally I think I would prefer to have a status that confirms that config.env is there when a new image is added (the PR that adds the new image). But I guess this might be too complex / not so much needed. So we could consider config.env a requirement for every image and just return non-zero status if the file is not there? WDYT?

@Jdubrick
Copy link
Contributor

Jdubrick commented Jan 6, 2025

Similar status has seen on other PRs #21 #20 #19 #18
Might be a good idea to group those updates so we can have less PRs generated from renovate? IIRC we can even do it for only patch/minor updates without risking combining a major update with minor/patch.
cc @Jdubrick

Agreed on your comment regarding the config.env, if we have other suggestions for handling the gh action push without needing to maintain a file like that I am open to hearing suggestions as well.
I can look into the grouping of the PRs this week since I am now back from PTO @thepetk

Ideally I think I would prefer to have a status that confirms that config.env is there when a new image is added (the PR that adds the new image). But I guess this might be too complex / not so much needed. So we could consider config.env a requirement for every image and just return non-zero status if the file is not there? WDYT?

I like that idea and don't think it'd be difficult to implement, I'll take a look at implementing that alongside the PR grouping :)

Copy link
Contributor

@thepetk thepetk left a comment

Choose a reason for hiding this comment

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

lgtm

@thepetk
Copy link
Contributor

thepetk commented Jan 23, 2025

I like the new grouping btw. Seems nice

@renovate renovate bot force-pushed the renovate/pypi-starlette-vulnerability branch from 11dda4e to d35bed0 Compare May 8, 2025 21:40
@renovate renovate bot force-pushed the renovate/pypi-starlette-vulnerability branch from d35bed0 to 3494e80 Compare August 3, 2025 15:37
@renovate renovate bot requested a review from a team as a code owner August 3, 2025 15:37
@renovate renovate bot changed the title Update dependency starlette to v0.40.0 [SECURITY] Update dependency starlette to v0.47.2 [SECURITY] Aug 3, 2025
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
@renovate renovate bot force-pushed the renovate/pypi-starlette-vulnerability branch from 3494e80 to 10c69cb Compare September 25, 2025 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants