fix(adapters): block responses are text/plain - #144
Conversation
StarletteResponseFactory.create_response built the response without a media type, so every block and error response (403, 400, 429, the Redis-unavailable 503, custom_error_responses messages) went out with no Content-Type while guard-core adds X-Content-Type-Options: nosniff. It now sets text/plain, as the Tornado adapter does; a custom_response_modifier that sets its own Content-Type still wins. Closes rennf93#143
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review. 📝 WalkthroughWalkthroughBlocked responses now use a plain-text media type by default. Middleware tests check default and custom blocked responses, the ChangesBlocked response content type
Priority: ⬇️ Low Estimated code review effort: 2 (Simple) | ~8 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to Blocked responses now default to plain text while custom response types and ordinary endpoint responses remain unaffected. No actionable merge-specific risk is established. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to Blocked responses now identify their body as plain text. The reviewed request path still blocks before reaching the application, and a custom response modifier can still choose another content type. No new security bypass was identified. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
rennf93
left a comment
There was a problem hiding this comment.
Verified: block responses now carry text/plain under the nosniff header, custom error messages keep the content type, and the custom_response_modifier still overrides it (all three covered by the new tests; full middleware suite passes locally). Note for follow-up: tornadoapi-guard, flaskapi-guard, and djangoapi-guard response factories have the same missing Content-Type, so the same fix is needed over there.
Delivers issue: #143
Description
StarletteResponseFactory.create_responsenow builds the response withmedia_type="text/plain", so block and error responses carryContent-Type: text/plain; charset=utf-8next to theX-Content-Type-Options: nosniffguard-core adds.guard/adapters.py: the media type oncreate_response. Every message response goes through it: the checks' 403/400/429, the Redis-unavailable 503, andcustom_error_responsesmessages.tests/test_middleware/test_block_response_content_type.py: new tests, listed below.Motivation and Context
Starlette only sets a Content-Type when it is given a media type, so these responses had none, while
nosnifftells the client not to guess one. The Tornado adapter already sendstext/plain; charset=utf-8from the same factory method. Acustom_response_modifierthat sets its own Content-Type (for problem+json, say) still wins, since it runs after the factory. Details and a repro in #143.Type of change
How Has This Been Tested
REDIS_URL=redis://localhost:6391 REDIS_PREFIX=test:fastapi_guard: pytest tests/test_middleware/test_block_response_content_type.py: 3 passed (Python 3.10.20, guard-core 4.0.5, FastAPI 0.141.1, Starlette 1.7.0, a throwaway local Redis). A blacklisted IP's 403 and acustom_error_responsesmessage aretext/plain; charset=utf-8withnosniff(both fail onmaster); a modifier that setsapplication/problem+jsonkeeps it.tests/live_smoke): 408 passed, 8 failed. The same 8 intest_security_middleware.pyfail onmasterin this environment, as in fix(middleware): resolve the route Starlette redirects a trailing-slash request to #142.ruff format --check,ruff check,mypy guardand on the new test,vulture,bandit,xenon,deptry: clean.status 403 | content-type: text/plain; charset=utf-8 | body: Forbidden.Checklist
Summary by CodeRabbit
nosniffprotection.