Skip to content

fix(middleware): apply_cors/apply_csrf compose instead of clobbering the middleware stack - #231

Merged
ZhuchkaTriplesix merged 1 commit into
devfrom
issue-209-middleware-stack-clobber
Sep 29, 2026
Merged

ZhuchkaTriplesix merged 1 commit into
devfrom
issue-209-middleware-stack-clobber

Conversation

@ZhuchkaTriplesix

Copy link
Copy Markdown
Member

Problem

App.set_middleware() replaces the entire single-slot request-middleware list. Both apply_cors() and apply_csrf() called it internally:

  • app.add_middleware(auth) followed by apply_cors(app, cfg) silently deleted auth.
  • apply_csrf(app, cfg) followed by apply_cors(app, cfg) silently deleted the CSRF guard.

No error, no warning — a composed security stack just lost a layer.

Fix

  • Wired up App.add_middleware(handler, phase="request"|"response"|"both") on the Python App class — the native add_middleware pymethod existed but had no Python-level entry point.
  • apply_cors() and apply_csrf() now call add_middleware() instead of set_middleware(), so they compose with anything already registered (including with each other) instead of replacing it.
  • set_middleware() now emits a warnings.warn when it would clobber existing add_middleware-registered middleware, for callers who still use the single-slot API directly.

Testing

New tests in tests/test_middleware.py:

  • test_add_middleware_then_apply_cors_does_not_clobber_auth
  • test_apply_csrf_then_apply_cors_compose_instead_of_clobbering
  • test_set_middleware_warns_when_clobbering_add_middleware

Updated tests/test_csrf_units.py's app stub (apply_csrf now calls add_middleware, not set_middleware).

  • Full suite: 164 passed (161 + 3 new), 1 skipped.
  • ruff check / ruff format --check: clean.

Closes #209

…the middleware stack

set_middleware() replaces the entire single-slot request-middleware
list, but apply_cors() and apply_csrf() both called it internally.
Calling add_middleware(auth) followed by apply_cors(...) silently
deleted the auth middleware; calling apply_csrf(...) followed by
apply_cors(...) silently deleted the CSRF guard. No error, no
warning — a composed security stack just lost a layer.

- Add App.add_middleware(handler, phase="request"|"response"|"both"),
  wiring the previously-unused native add_middleware pymethod.
- apply_cors() and apply_csrf() now use add_middleware() instead of
  set_middleware(), so they compose with anything already registered
  (including with each other) instead of replacing it.
- set_middleware() now warns when it would clobber existing
  middleware registered via add_middleware, for callers who still use
  the single-slot API directly.

Closes #209
@ZhuchkaTriplesix
ZhuchkaTriplesix merged commit a4ac692 into dev Sep 29, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant