Skip to content

chore(deps): bump starlette from 0.49.1 to 1.3.1#3116

Open
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/uv/starlette-1.3.1
Open

chore(deps): bump starlette from 0.49.1 to 1.3.1#3116
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/uv/starlette-1.3.1

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Jul 16, 2026

Copy link
Copy Markdown
Contributor

Bumps starlette from 0.49.1 to 1.3.1.

Release notes

Sourced from starlette's releases.

Version 1.3.1

What's Changed

Full Changelog: Kludex/starlette@1.3.0...1.3.1

Version 1.3.0

What's Changed

New Contributors

Full Changelog: Kludex/starlette@1.2.1...1.3.0

Version 1.2.1

What's Changed

New Contributors

Full Changelog: Kludex/starlette@1.2.0...1.2.1

Version 1.2.0

What's Changed

Full Changelog: Kludex/starlette@1.1.0...1.2.0

Version 1.1.0

... (truncated)

Changelog

Sourced from starlette's changelog.

1.3.1 (June 12, 2026)

Fixed

  • Enforce max_fields and max_part_size in FormParser #3329.
  • Enforce FormParser limits in parser callbacks #3331.

1.3.0 (June 11, 2026)

Added

  • Add httpx2 to the full extra #3323.
  • Annotate the URLPath protocol parameter with Literal #3285.

Fixed

  • Build request.url from structured components #3326.
  • Clamp oversized suffix ranges in FileResponse #3307.
  • Catch OSError alongside MultiPartException when closing temp files #3191.
  • Avoid collapsing exception groups raised from user code #2830.
  • Use removeprefix to strip the weak ETag indicator in is_not_modified #3193.
  • Fix IndexError in URL.replace() on a URL with no authority #3317.
  • Adjust testclient typing and warnings #3322.

1.2.1 (May 31, 2026)

Fixed

  • Use httpx2 for type checking in the testclient module #3304.
  • Add assert error for requires() when the request parameter is not a Request type #3298.

1.2.0 (May 28, 2026)

Added

  • Support httpx2 in the test client #3291.

1.1.0 (May 23, 2026)

Added

  • Use "application/octet-stream" as the FileResponse media type fallback #3283.

Fixed

  • Only dispatch standard HTTP verbs in HTTPEndpoint #3286.
  • Reject absolute paths in StaticFiles.lookup_path #3287.

1.0.1 (May 21, 2026)

... (truncated)

Commits
  • 8ebffd0 Version 1.3.1 (#3330)
  • 25b8e17 Enforce FormParser limits in parser callbacks (#3331)
  • dba1c4b Enforce max_fields and max_part_size in FormParser (#3329)
  • 45e51dc Use StarletteDeprecationWarning instead of DeprecationWarning (#3119)
  • 5f8610c Version 1.3.0 (#3327)
  • 167b585 Build request.url from structured components (#3326)
  • 3730925 Use removeprefix to strip weak ETag indicator in is_not_modified (#3193)
  • e6f7ad1 avoid collapsing exception groups from user code (#2830)
  • 115228f Annotate URLPath protocol parameter with Literal (#3285)
  • 113f193 docs: replace inline ASGI server list with link to canonical implemen… (#3204)
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    You can disable automated security fix PRs for this repo from the Security Alerts page.

Bumps [starlette](https://github.com/Kludex/starlette) from 0.49.1 to 1.3.1.
- [Release notes](https://github.com/Kludex/starlette/releases)
- [Changelog](https://github.com/Kludex/starlette/blob/main/docs/release-notes.md)
- [Commits](Kludex/starlette@0.49.1...1.3.1)

---
updated-dependencies:
- dependency-name: starlette
  dependency-version: 1.3.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file python:uv Pull requests that update python:uv code labels Jul 16, 2026

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — lockfile-only Dependabot bump of starlette to 1.3.1. The SDK's own constraint (starlette>=0.27, unbounded) means end users already resolve 1.3.1; this only updates the CI/dev pin, and the full test matrix runs against it. The one inline note is a non-blocking follow-up suggestion, not a merge blocker.

Extended reasoning...

Overview

This PR is a single-file Dependabot change: uv.lock bumps starlette from 0.49.1 to 1.3.1. No source code, no pyproject.toml constraint change. The SDK's runtime requirement remains starlette>=0.27 (>=0.48 on 3.14) with no upper bound, so published-package users already resolve 1.3.1 today — this pin only affects the SDK's own CI/dev environment.

Security risks

The delta is upstream hardening (FormParser max_fields/max_part_size enforcement, StaticFiles absolute-path rejection, FileResponse range clamping) — security-positive rather than risky. The one behavioral interaction found is the inline nit: starlette's new 1 MB form-field limit raises an HTTPException(400) that the OAuth handlers' except ValidationError blocks don't translate into the RFC 6749 JSON error shape. The trigger is adversarial (>1 MB field or >1000 fields), the status code is still a correct 400, and the exposure exists independently of this PR given the unbounded floor — so it's a follow-up, not a blocker.

Level of scrutiny

Lockfile-only dependency bumps warrant moderate scrutiny focused on behavioral deltas in the upgraded package, which the bug hunting system performed: all imported starlette symbols verified present in 1.3.1, removed 1.0 APIs (on_startup/on_event/@app.route/WSGIMiddleware) confirmed unused, sse-starlette 3.0.2 compatibility checked, and the request.url structured-components change confirmed not to touch server-side SDK code. The full CI matrix (3.10–3.14 × ubuntu/windows, 100% coverage gate) runs against the new pin, which is the definitive compatibility check.

Other factors

No human reviewer comments and no prior bot reviews on this PR. The major-version jump (0.49 → 1.3) looks larger than it is — the audited delta shows no removed APIs in use and the repo does not use starlette's multipart/form features outside the OAuth handlers flagged inline. Approving with the inline nit standing as a suggested follow-up.

Comment thread uv.lock
Comment on lines 2470 to 2480
name = "starlette"
version = "0.49.1"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1b/3f/507c21db33b66fb027a332f2cb3abbbe924cc3a79ced12f01ed8645955c9/starlette-0.49.1.tar.gz", hash = "sha256:481a43b71e24ed8c43b11ea02f5353d77840e01480881b8cb5a26b8cae64a8cb", size = 2654703, upload-time = "2025-10-28T17:34:10.928Z" }
sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/51/da/545b75d420bb23b5d494b0517757b351963e974e79933f01e05c929f20a6/starlette-0.49.1-py3-none-any.whl", hash = "sha256:d92ce9f07e4a3caa3ac13a79523bd18e3bc0042bb8ff2d759a8e7dd0e1859875", size = 74175, upload-time = "2025-10-28T17:34:09.13Z" },
{ url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" },
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Starlette 1.3.1 newly enforces max_part_size=1MB / max_fields=1000 on application/x-www-form-urlencoded bodies (Kludex/starlette#3329, #3331), raising an HTTPException(400) that the SDK's OAuth handlers (token.py, revoke.py, authorize.py POST, client_auth.py) don't catch — they only catch pydantic ValidationError around request.form(), so oversized posts to /token or /revoke now return a text/plain 400 instead of the RFC 6749 §5.2 JSON error object. Not a merge blocker (pyproject's unbounded starlette>=0.27 floor means users can already resolve 1.3.1, and the trigger is adversarial: a >1MB field or >1000 fields), but a follow-up could catch starlette's HTTPException around request.form() in these handlers and translate it into the OAuth invalid_request JSON shape.

Extended reasoning...

What changed in starlette

In starlette 0.49.1, FormParser (the parser for application/x-www-form-urlencoded bodies) had no size limitsRequest._get_form simply ran FormParser(self.headers, self.stream()); await form_parser.parse() with no exception path. Starting in 1.3.1 (Kludex/starlette#3329 and #3331), FormParser enforces max_fields=1000 and max_part_size=1MB per field (verified in the installed wheel, formparsers.py:82-97). Exceeding either limit raises MultiPartException, which Request._get_form converts into a starlette HTTPException(status_code=400, detail='Field exceeded maximum size of 1024KB.' / 'Too many fields...') when app is in scope (requests.py:296-308).

Why the SDK's OAuth handlers are affected

The SDK's OAuth handlers all call await request.form() inside try blocks that catch only pydantic ValidationError (or AuthenticationError further up):

  • src/mcp/server/auth/handlers/token.py:121
  • src/mcp/server/auth/handlers/revoke.py:50
  • src/mcp/server/auth/handlers/authorize.py:150 (POST branch)
  • src/mcp/server/auth/middleware/client_auth.py:54 (called by token/revoke handlers)

These handlers deliberately construct RFC 6749 §5.2-conformant JSON error objects (TokenErrorResponse / RevocationErrorResponse via PydanticJSONResponse, with Cache-Control: no-store). The new starlette HTTPException is not caught by any of them, so it escapes to the Starlette app's ExceptionMiddleware and is rendered as a text/plain 400 response. If the handlers are composed as raw ASGI without a Starlette app in scope, the raw MultiPartException propagates and produces a 500 instead.

Step-by-step proof

  1. A client POSTs to /token with Content-Type: application/x-www-form-urlencoded and a body containing one field larger than 1 MiB (e.g. a huge client_assertion value): grant_type=client_credentials&client_assertion=AAAA...(>1MB).
  2. TokenHandler.handle (token.py:121) calls await request.form() inside try: ... except ValidationError.
  3. In starlette 1.3.1, FormParser.parse() accumulates the field value, hits the 1 MiB max_part_size check added in Enforce FormParser limits in parser callbacks Kludex/starlette#3331, and raises MultiPartException('Field exceeded maximum size of 1024KB.').
  4. Request._get_form catches it and re-raises as starlette.exceptions.HTTPException(400) (because the request is served by a Starlette app).
  5. This is not a ValidationError, so the handler's except doesn't fire — the carefully built TokenErrorResponse(error='invalid_request', ...) JSON path is bypassed.
  6. ExceptionMiddleware catches the HTTPException and returns 400 with body Field exceeded maximum size of 1024KB. as text/plain — violating RFC 6749 §5.2, which requires the token endpoint to return a JSON error object.

Under 0.49.1, the same request parses successfully (unbounded buffering) and reaches the handler's normal validation path — so the changed error shape is introduced by this bump.

Why this is not a merge blocker

  • pyproject.toml constrains starlette>=0.27 with no upper bound, so end users installing the published mcp package already resolve 1.3.1 today regardless of this PR — the lockfile only pins the SDK's own CI/dev environment. Blocking this bump would shield no one.
  • The trigger is adversarial or an extreme edge case: no realistic OAuth client sends a single >1 MiB form field or >1000 fields (even large RFC 7523 client_assertion JWTs are orders of magnitude below 1 MiB). The status code is still an RFC-correct 400; only the body shape/content-type differ.
  • The upstream change is intentional DoS hardening — 0.49.1's unbounded in-memory buffering of urlencoded bodies was strictly worse. Real deployments behind reverse proxies (e.g. nginx's 1 MB default body limit) would often preempt the app with a 413 anyway.

Suggested follow-up fix

In the four handlers listed above, catch starlette's HTTPException (or MultiPartException) around await request.form() and translate it into the OAuth invalid_request JSON error shape, e.g. TokenErrorResponse(error='invalid_request', error_description='request body too large') with status 400. Alternatively, pass explicit max_part_size/max_fields to request.form() and handle the failure there.

For completeness: the rest of the 0.49.1 → 1.3.1 delta was audited against SDK usage and no other affected paths were found — all imported starlette symbols still exist, removed 1.0 APIs (on_startup/on_event/@app.route/WSGIMiddleware) are unused, sse-starlette 3.0.2's imports remain valid, and request.url host-header behavior changes (starlette#3326) don't touch server-side SDK code.

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 python:uv Pull requests that update python:uv code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants