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
Published August 28, 2026Reviewed 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.10.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

high

How Denial of Service via Infinite Loop Happens in JavaScript Dependencies and How to Fix It

CVE-2026-67213 is a high-severity denial of service vulnerability in nanoid before version 5.1.6 that triggers an infinite loop during random ID generation when processing specially crafted input. We upgraded nanoid across the entire dependency tree to patch this flaw and prevent attackers from freezing application threads. This fix ensures that ID generation remains resilient even when handling adversarial input patterns.

high

How Sensitive Data Exposure happens in Zotero plugins and how to fix it

A high-severity data exposure vulnerability in `Zotero.ts` automatically transmitted complete document metadata—including private notes, attachment paths, and tags—to external LLM services without user consent. The fix replaces broad `item.toJSON()` serialization with explicit field selection, sending only essential bibliographic data.

high

How missing dependency update cooldowns happen in GitHub Dependabot configurations and how to fix it

A semgrep scan flagged `.github/dependabot.yml` for lacking a cooldown period, meaning Dependabot would immediately propose updates to brand-new package versions across npm, Bundler, and Docker ecosystems. The fix adds a `cooldown: default-days: 7` block to every `package-ecosystem` entry, forcing a one-week waiting period before newly published releases are considered — reducing exposure to malicious or unstable package drops.

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

critical

How Unbounded WebSocket Message Handling Causes Resource Exhaustion in Node.js and How to Fix It

The WebSocketCrossServerAdapter class in a popular Node.js WebSocket library lacked any rate limiting on inbound messages, allowing attackers to flood Redis nodes and WebSocket servers with high-volume traffic. The fix introduces a configurable `rateLimit` option that caps messages per connection per second, preventing resource exhaustion while preserving legitimate functionality.

critical

How Remote Code Execution Happens in Handlebars Template Compilation and How to Fix It

CVE-2026-33937 is a critical remote code execution vulnerability in Handlebars.js that allows attackers to execute arbitrary code by passing maliciously crafted Abstract Syntax Tree (AST) objects to the compile() function. The vulnerability was patched in version 4.7.9, and we've upgraded to protect against this threat vector.