Skip to content

Bug: CORS middleware order causes headers to be stripped on rate-limited responses #12

Description

@AdityaPatil22

Description

In Backend/main.py, the middleware is added in this order:

app.add_middleware(SecurityHeadersMiddleware)    # 1st added = outermost
app.add_middleware(APIKeyScrubMiddleware)         # 2nd
app.add_middleware(RateLimitMiddleware, ...)      # 3rd
app.add_middleware(CORSMiddleware, ...)           # 4th added = innermost

In Starlette/FastAPI, middleware executes in reverse order of add_middleware calls (LIFO). So the actual request flow is:

Request → CORS → RateLimit → APIKeyScrub → SecurityHeaders → Route

When RateLimitMiddleware returns a 429 response directly (without calling call_next), the response bypasses CORSMiddleware's response processing. This means the 429 response is missing CORS headers (Access-Control-Allow-Origin, etc.).

Impact

  • Frontend receives a 429 rate-limit response but the browser blocks it due to CORS
  • The user sees a cryptic "CORS error" in the console instead of a helpful "rate limit exceeded" message
  • Makes it impossible for the frontend to show a proper rate-limit notification

Steps to Reproduce

  1. Hit the API rapidly to trigger rate limiting
  2. Observe in browser dev tools: the 429 response is blocked by CORS
  3. Frontend sees a network error instead of the 429 status + JSON body

Expected Behavior

The CORS middleware should be the outermost middleware so its headers are always applied, even on short-circuit responses from inner middleware. Move CORSMiddleware to be added first:

app.add_middleware(CORSMiddleware, ...)           # Add first = outermost
app.add_middleware(SecurityHeadersMiddleware)
app.add_middleware(APIKeyScrubMiddleware)
app.add_middleware(RateLimitMiddleware, ...)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions