Back to Blog
critical SEVERITY6 min read

How Rate Limiting Vulnerabilities Happen in FastAPI and How to Fix Them

A critical denial-of-service vulnerability was discovered in a FastAPI application controlling Tesla Powerwall systems, where all 113+ API endpoints—including critical control endpoints for `/control/reserve` and `/control/mode`—lacked any rate limiting protection. An attacker could flood these endpoints with unlimited requests, exhausting server resources and disrupting powerwall monitoring and control operations. The fix introduces a configurable, pure-ASGI rate limiting middleware that can be

O
By Orbis AppSec
Published August 31, 2026Reviewed August 31, 2026

Answer Summary

This is a Denial of Service (DoS) vulnerability caused by missing rate limiting in a FastAPI application (CWE-770: Allocation of Resources Without Limits). The Python application exposed 113+ endpoints including critical powerwall control APIs without request throttling. The fix implements a configurable fixed-window rate limiting middleware (`_RateLimitMiddleware`) that can be enabled via the `PW_RATE_LIMIT_ENABLED` environment variable, with tunable limits for requests per window, window duration, and maximum tracked client buckets.

Vulnerability at a Glance

cweCWE-770
fixImplemented configurable ASGI rate limiting middleware with environment variable controls
riskRemote attackers can exhaust server resources and disrupt powerwall control operations
languagePython (FastAPI)
root causeNo request throttling middleware on any of the 113+ API endpoints
vulnerabilityMissing Rate Limiting (Denial of Service)

Introduction

In a FastAPI application designed to monitor and control Tesla Powerwall systems, we discovered a critical denial-of-service vulnerability in app/main.py. The application exposed over 113 API endpoints—including sensitive control endpoints like /control/reserve and /control/mode—without any form of request throttling or rate limiting.

This meant that any attacker with network access to the application could send unlimited HTTP requests to any endpoint, potentially exhausting CPU, memory, and database connections. For an application controlling home energy storage systems, this vulnerability could disrupt critical powerwall monitoring and control operations, leaving users unable to manage their energy systems during peak demand or outages.

The vulnerable code pattern was straightforward: a FastAPI application with numerous routes but no middleware to limit request rates. While the application had proper authentication in place, it lacked the crucial defense-in-depth measure of rate limiting.

The Vulnerability Explained

What Makes This Dangerous?

The FastAPI application in app/main.py instantiated routes for various functionalities without any rate limiting middleware in the ASGI middleware stack. This created a situation where:

  1. Control endpoints (/control/reserve, /control/mode) could be flooded with commands
  2. Data endpoints (/api/gateways/*, /api/timeseries/*) could be overwhelmed with read requests
  3. Health endpoints (/health) could be targeted to mask actual service degradation

The original application structure looked something like this:

from fastapi import FastAPI

app = FastAPI()

# 113+ endpoints defined without any rate limiting
@app.post("/control/reserve")
async def control_reserve():
    # Critical powerwall control logic
    pass

@app.post("/control/mode")
async def control_mode(mode: dict):
    # Mode switching logic
    pass

@app.get("/api/gateways/status")
async def gateway_status():
    # Gateway status retrieval
    pass

Attack Scenario

An attacker targeting this powerwall monitoring system could execute a denial-of-service attack with a simple script:

import asyncio
import aiohttp

async def flood_endpoint():
    async with aiohttp.ClientSession() as session:
        while True:
            # Flood the control endpoint
            await session.post("http://target/control/mode", 
                             json={"mode": "self_consumption"})

This attack would:
1. Exhaust the server's ability to process legitimate requests
2. Potentially cause database connection pool exhaustion
3. Disrupt real-time powerwall monitoring during critical periods
4. Prevent legitimate users from controlling their energy systems

The DESIGN.md file explicitly documented this as a critical issue, noting that "a compromised token could flood the Powerwall with commands."

The Fix

The fix introduces a configurable, pure-ASGI rate limiting middleware called _RateLimitMiddleware that can be enabled via environment variables. This approach was chosen over the originally suggested slowapi route decorator for several important reasons:

Key Design Decisions

  1. Global application rather than per-route decoration
  2. Disabled by default to avoid breaking existing integrations (Powerwall-Dashboard, Grafana, Home Assistant polling)
  3. Configurable via environment variables for flexibility

The updated DESIGN.md reflects this resolution:

#### 1. ✅ No Rate Limiting on Control Endpoints — Addressed

**Location**: [app/api/legacy.py](app/api/legacy.py#L73-L87), [app/main.py](app/main.py) (`_RateLimitMiddleware`)

**Resolution**: A first-party, pure-ASGI, fixed-window rate limiter is available, 
applied globally (not just `/control/*`) rather than the originally-suggested 
`slowapi` route decorator. It is **disabled by default** (`PW_RATE_LIMIT_ENABLED`) 
so it never regresses the common Powerwall-Dashboard/Grafana/Home Assistant polling 
use case.

Configuration Options

The middleware is controlled through these environment variables:

Variable Purpose
PW_RATE_LIMIT_ENABLED Enable/disable rate limiting (default: off)
PW_RATE_LIMIT_MAX_REQUESTS Maximum requests per window
PW_RATE_LIMIT_WINDOW_SECONDS Time window duration
PW_RATE_LIMIT_MAX_BUCKETS Maximum tracked client buckets (memory bound)

Before vs. After

Before: No rate limiting middleware in the ASGI stack

app = FastAPI()
# All 113+ endpoints accessible without throttling

After: Configurable rate limiting middleware available

app = FastAPI()
# _RateLimitMiddleware added to middleware stack
# Controlled via PW_RATE_LIMIT_ENABLED environment variable
# Returns HTTP 429 when limits exceeded

The fix also updated the priority table in DESIGN.md:

| Priority | Area | Effort |
|----------|------|--------|
| ~~High~~ Done | ~~Rate limiting on control endpoints~~ Available via `PW_RATE_LIMIT_ENABLED` (default off) | Low |

Key Takeaways

  • All 113+ endpoints in app/main.py were vulnerable to unlimited request flooding before this fix
  • Control endpoints like /control/reserve and /control/mode posed the highest risk as they directly affect powerwall operations
  • The fix uses a fixed-window algorithm with configurable parameters via environment variables
  • Disabled by default preserves backward compatibility with existing monitoring integrations
  • Memory is bounded via PW_RATE_LIMIT_MAX_BUCKETS to prevent the rate limiter from becoming an attack vector itself

How Orbis AppSec Detected This

  • Source: HTTP requests from any network client with access to the application
  • Sink: All 113+ API endpoints in app/main.py including /control/reserve, /control/mode, /api/gateways/*, and /api/timeseries/*
  • Missing control: No rate limiting middleware in the ASGI middleware stack to throttle incoming requests
  • CWE: CWE-770 (Allocation of Resources Without Limits or Throttling)
  • Fix: Implemented _RateLimitMiddleware as a configurable, pure-ASGI fixed-window rate limiter controlled via PW_RATE_LIMIT_ENABLED environment variable

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

This vulnerability demonstrates why rate limiting is a critical security control for any API, especially those controlling physical systems like energy storage. The fix provides a flexible, opt-in solution that protects against denial-of-service attacks while maintaining compatibility with existing monitoring integrations.

When building APIs with FastAPI or any other framework, always consider:
1. What happens if an endpoint receives thousands of requests per second?
2. Which endpoints are most critical and need the strictest limits?
3. How will rate limiting interact with legitimate high-frequency clients?

The configurable approach taken in this fix—disabled by default with environment variable controls—provides a template for implementing rate limiting in applications with diverse deployment scenarios.

Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #84

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.