Skip to content

Require an admin session for ActiveStorage direct uploads - #85

Open
xrendan wants to merge 1 commit into
mainfrom
fix/lock-down-direct-uploads
Open

Require an admin session for ActiveStorage direct uploads#85
xrendan wants to merge 1 commit into
mainfrom
fix/lock-down-direct-uploads

Conversation

@xrendan

@xrendan xrendan commented Jul 28, 2026

Copy link
Copy Markdown
Member

Summary

POST /rails/active_storage/direct_uploads is drawn by Rails with no authentication and is currently reachable in production. Anyone can create ActiveStorage::Blob records and obtain presigned R2 PUT URLs — i.e. free writes into our storage bucket plus unbounded junk rows in active_storage_blobs.

Nothing in the app uses direct uploads anymore: the admin markdown editor uploads through POST /admin/uploads (#84), and all other file fields are plain multipart form uploads. Rather than deleting the route (draw_routes = false would also remove the blob-serving routes we rely on), this gates the endpoint behind the same admin check as Admin::BaseController, keeping it usable from the admin if direct uploads are ever wanted for large files.

Changes

  • config/initializers/active_storage_direct_uploads.rb: decorates ActiveStorage::DirectUploadsController in to_prepare with a before_action requiring a signed-in admin (warden user with admin?), returning 401 otherwise. Uses a named method so the callback dedupes if to_prepare runs again on reload.

Testing

  • New integration tests: anonymous → 401 with no blob created; signed-in non-admin member → 401; signed-in admin → blob created and direct_upload payload returned.
  • Full suite: 753 runs, 0 failures. Rubocop clean.

POST /rails/active_storage/direct_uploads ships unauthenticated, so
anyone could create blob records and obtain presigned R2 PUT URLs
(free storage abuse). Nothing in the app uses direct uploads — the
admin markdown editor proxies through /admin/uploads — so gate the
endpoint behind the same admin check as Admin::BaseController instead
of leaving it open. Named before_action keeps the decoration
idempotent under to_prepare reloads.
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