Back to Blog
high SEVERITY8 min read

How Silent Form Limit Bypasses Happen in Starlette and How to Fix Them

CVE-2026-54283 is a high-severity Denial of Service vulnerability in Starlette where form size limits set on `request.form()` were silently ignored for `application/x-www-form-urlencoded` content, allowing attackers to submit arbitrarily large payloads that could exhaust server resources. The fix upgrades Starlette from version 0.49.1 to 0.50.0, where the form parser correctly enforces configured limits for both multipart and URL-encoded content types. This change was applied to `agent/sandbox/u

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published August 28, 2026•Reviewed August 28, 2026

Answer Summary

CVE-2026-54283 is a high-severity Denial of Service (DoS) vulnerability in the Starlette Python web framework (CWE-770: Allocation of Resources Without Limits or Throttling). In versions prior to 0.50.0, size limits passed to `request.form()` were silently ignored when the request used `application/x-www-form-urlencoded` encoding, meaning an attacker could send unbounded form payloads to exhaust server memory or CPU. The fix is to upgrade Starlette from 0.49.1 to 0.50.0, which correctly enforces the configured limits for all form content types.

Vulnerability at a Glance

cweCWE-770 (Allocation of Resources Without Limits or Throttling)
fixUpgrade Starlette from 0.49.1 to 0.50.0 to enforce limits for all form content types
riskAttackers can send arbitrarily large URL-encoded form payloads to exhaust server resources
languagePython
root causeStarlette's form parser applied size limits only to multipart forms, not application/x-www-form-urlencoded
vulnerabilityDenial of Service via silently ignored form size limits

How Silent Form Limit Bypasses Happen in Starlette and How to Fix Them


Vulnerability at a Glance

Field Detail
Vulnerability Denial of Service via silently ignored form size limits
CWE CWE-770 — Allocation of Resources Without Limits or Throttling
Language Python
Framework Starlette
Risk Unbounded memory consumption from URL-encoded form payloads
Root Cause Form size limits not enforced for application/x-www-form-urlencoded
Fix Upgrade Starlette from 0.49.1 → 0.50.0

Introduction

The agent/sandbox/uv.lock file in this repository pins Starlette at version 0.49.1 — a version that contains a subtle but dangerous flaw in how it processes HTML form submissions. When application code calls request.form() with size-limiting parameters, developers reasonably expect those limits to be enforced. In Starlette 0.49.1, however, those limits are silently ignored for the application/x-www-form-urlencoded content type, the default encoding used by virtually every HTML <form> element on the web.

This is the kind of vulnerability that's particularly insidious: the code looks safe, the developer believes it's protected, but the protection simply isn't there. An attacker who knows this can bypass what appears to be a hardened endpoint and submit payloads large enough to exhaust server memory or CPU — a classic Denial of Service attack requiring nothing more than an HTTP client.


The Vulnerability Explained

What request.form() Is Supposed to Do

Starlette's request.form() is an async method that parses incoming form data from HTTP request bodies. It supports two content types:

  • multipart/form-data — used for file uploads
  • application/x-www-form-urlencoded — the default for standard HTML forms

Developers can pass limit parameters to cap how much data is processed:

# Developer's intent: limit form fields to prevent resource exhaustion
form_data = await request.form(
    max_fields=100,
    max_files=10,
    max_part_size=1_000_000  # 1 MB per part
)

This looks correct. The problem is that in Starlette 0.49.1, these limits were only wired into the multipart parser. When the incoming Content-Type header was application/x-www-form-urlencoded, the parser read the entire body without checking any of those configured limits.

The Silent Failure

The vulnerability is not a crash or an exception — it's silence. The limits are accepted as valid arguments, no warning is raised, no error is thrown, and the developer gets no feedback that their carefully configured guardrails are doing nothing. This is what makes CVE-2026-54283 especially dangerous: it creates a false sense of security.

A vulnerable endpoint might look like this:

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

async def submit_form(request):
    # In Starlette 0.49.1, max_fields is ignored for
    # application/x-www-form-urlencoded — limits are silently dropped
    form = await request.form(max_fields=50, max_part_size=64_000)
    return JSONResponse({"status": "ok"})

app = Starlette(routes=[Route("/submit", submit_form, methods=["POST"])])

How an Attacker Exploits This

An attacker doesn't need authentication, special knowledge of the application, or sophisticated tooling. They only need to know the endpoint accepts form submissions. A simple attack looks like this:

# Generate a massive URL-encoded form payload and POST it
python3 -c "
import urllib.parse, sys
# Create a payload with thousands of fields and large values
payload = '&'.join(f'field_{i}=' + 'A' * 10000 for i in range(10000))
print(payload)
" | curl -s -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-binary @- \
  https://target-app.example.com/submit

Because Starlette 0.49.1 ignores max_fields and max_part_size for URL-encoded bodies, this payload — roughly 100 MB of form data — is read entirely into memory and parsed. Repeat this across multiple concurrent connections and the server's memory is exhausted, taking down the application for legitimate users.

Real-World Impact for This Repository

The vulnerable dependency lives in agent/sandbox/uv.lock, which governs the Python environment for the agent's sandbox component. If this component exposes any HTTP endpoints that process form submissions (a common pattern in agent frameworks that accept configuration, commands, or data via web interfaces), those endpoints are exposed to this resource exhaustion attack without any of the configured limits providing protection.


The Fix

What Changed

The fix is a targeted dependency upgrade in agent/sandbox/uv.lock, bumping Starlette from 0.49.1 to 0.50.0:

 [[package]]
 name = "starlette"
-version = "0.49.1"
+version = "0.50.0"
 source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" }
 dependencies = [
     { name = "anyio" },
 ]
-sdist = { url = "...starlette-0.49.1.tar.gz", hash = "sha256:481a43b71e24ed8c43b11ea02f5353d77840e01480881b8cb5a26b8cae64a8cb" }
+sdist = { url = "...starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca" }
 wheels = [
-    { url = "...starlette-0.49.1-py3-none-any.whl", hash = "sha256:d92ce9f07e4a3caa3ac13a79523bd18e3bc0042bb8ff2d759a8e7dd0e1859875" }
+    { url = "...starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca" }
 ]

What Starlette 0.50.0 Actually Fixes

In version 0.50.0, Starlette's form parsing logic was updated so that limits passed to request.form() are enforced for both multipart/form-data and application/x-www-form-urlencoded content types. The URL-encoded form parser now respects max_fields and max_part_size, raising appropriate errors when payloads exceed configured thresholds rather than silently consuming them.

After the upgrade, the same developer code that was previously unprotected:

form = await request.form(max_fields=50, max_part_size=64_000)

...now actually enforces those limits regardless of whether the client sends multipart/form-data or application/x-www-form-urlencoded. An oversized URL-encoded payload will be rejected before it's fully read into memory.

Why Only the Lock File Changed

The change is confined to agent/sandbox/uv.lock because uv.lock is the authoritative record of exactly which package versions are installed in the sandbox environment. Updating this file is the correct and complete way to deploy the patched version — no application code changes are required because the fix lives entirely within the Starlette library itself.


Key Takeaways

  • Silent failures are the most dangerous kind: Starlette 0.49.1 accepted max_fields and max_part_size parameters without error but ignored them for URL-encoded forms — giving developers false confidence their endpoints were protected.
  • application/x-www-form-urlencoded is the default form encoding: This is not an exotic edge case. Standard HTML <form> elements use this content type by default, meaning the vulnerable code path was the most common one.
  • Lock files enable precise vulnerability detection: Because agent/sandbox/uv.lock pins the exact version 0.49.1, Trivy could definitively identify the vulnerable package and flag it for remediation.
  • The fix requires no application code changes: Upgrading to Starlette 0.50.0 is sufficient — the limit enforcement logic lives in the library, so existing calls to request.form() with limit parameters automatically gain correct behavior.
  • Always validate that resource limits work with a test: Setting a limit is not the same as enforcing a limit. A simple integration test that sends an oversized payload would have caught this bypass immediately.

How Orbis AppSec Detected This

  • Source: Incoming HTTP request body with Content-Type: application/x-www-form-urlencoded, containing an attacker-controlled payload of arbitrary size
  • Sink: request.form() in Starlette's URL-encoded form parser (starlette/formparsers.py), which allocated memory proportional to the full request body size without enforcing the max_fields or max_part_size limits passed by the caller
  • Missing control: Enforcement of developer-configured size limits for the application/x-www-form-urlencoded code path — limits were checked only in the multipart parser branch
  • CWE: CWE-770 — Allocation of Resources Without Limits or Throttling
  • Fix: Upgraded Starlette from 0.49.1 to 0.50.0 in agent/sandbox/uv.lock, where the URL-encoded form parser correctly enforces all configured limits

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

CVE-2026-54283 is a reminder that security controls are only valuable if they're actually enforced. In Starlette 0.49.1, the request.form() API accepted resource limit parameters in good faith but silently discarded them for URL-encoded form bodies — the most common form encoding on the web. Any endpoint that relied on those limits for protection against resource exhaustion was, in practice, unprotected.

The fix is straightforward: upgrade to Starlette 0.50.0, where limits are enforced uniformly across all form content types. But the broader lesson is architectural: resource limits should be tested, not just configured; they should be layered (proxy + framework + application); and dependency scanners should be part of every CI pipeline so that vulnerabilities like this are caught before they reach production.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #18947

Related Articles

medium

path-to-regexp 0.1.12 DoS: Catastrophic Backtracking on Malformed URL

path-to-regexp version 0.1.12 contains a regular expression engine vulnerability where maliciously crafted URL parameters trigger exponential backtracking, causing CPU exhaustion and service unavailability. Upgrading to version 0.1.13 eliminates the vulnerable pattern from the parsing logic.

critical

CVE-2026-59873: node-tar 7.5.11 DoS via Crafted Gzip Bomb

node-tar versions 7.5.11 through 7.5.18 are vulnerable to a denial-of-service attack through maliciously crafted gzip archives that decompress to disproportionately large sizes. An attacker can exploit this to exhaust memory and CPU resources by submitting a small, highly compressed archive that expands beyond configured limits during extraction.

high

MapManager.get() Race Condition Duplicates API Requests

The MapManager's `get(mapUid, cache)` method used a check-then-act pattern that permitted multiple concurrent requests to pass the cache miss check simultaneously, triggering redundant API calls and risking cache corruption. The fix introduces a `_pending` promise map to deduplicate in-flight fetches for identical map UIDs.

critical

Lampa Desktop Auto-Update Heuristic Bypass: Execution of Unverified

Lampa Desktop's auto-update mechanism downloaded JavaScript and CSS from `raw.githubusercontent.com` using only heuristic validation—file size thresholds and string pattern matching—that attackers could trivially satisfy. The fix introduces cryptographic integrity verification by cross-referencing Git blob hashes from the GitHub Contents API, ensuring downloaded code matches the repository's authoritative state before execution.

high

adm-zip 0.6.0 Preserves SUID Bits From ZIPs: CVE-2026-102282

The `adm-zip` dependency resolved to 0.6.0 in this project's dependency tree, a version affected by CVE-2026-102282: during extraction it applies the Unix permission bits stored in each ZIP entry's external file attributes verbatim, including the setuid (`04000`), setgid (`02000`), and sticky bits. An attacker who controls an archive passed to `extractAllTo()` or `extractEntryTo()` can therefore have the extractor create a setuid binary owned by whatever user the extraction process runs as. The

high

requestInput() Type Confusion: NaN and Object Bypass in JavaScript

The `requestInput()` utility function lacked validation on its `type` parameter and failed to handle `NaN` results from float conversions, creating a type confusion weakness. An attacker could supply malformed inputs that propagate unhandled `NaN` values or unexpected object types through the type system. The fix adds explicit guards against `NaN` type parameters and rejects non-primitive type values.