From 354bccd6e8542548cea09bfb3ef22879d743b42e Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Mon, 18 May 2026 17:51:50 +0300 Subject: [PATCH] handle dangerous extensions --- .../active_storage_blobs_proxy_controller.rb | 8 ++++ ...e_storage_blobs_proxy_legacy_controller.rb | 6 +++ app/controllers/user_initials_controller.rb | 6 +++ app/controllers/user_signatures_controller.rb | 6 +++ lib/submitters/normalize_values.rb | 38 +++++++++++++------ 5 files changed, 53 insertions(+), 11 deletions(-) diff --git a/app/controllers/api/active_storage_blobs_proxy_controller.rb b/app/controllers/api/active_storage_blobs_proxy_controller.rb index 3fc0dd5e..4198f380 100644 --- a/app/controllers/api/active_storage_blobs_proxy_controller.rb +++ b/app/controllers/api/active_storage_blobs_proxy_controller.rb @@ -11,6 +11,7 @@ module Api before_action :set_noindex_headers before_action :set_security_headers + # rubocop:disable Metrics def show blob_uuid, purp, exp = ApplicationRecord.signed_id_verifier.verified(params[:signed_uuid]) @@ -22,6 +23,12 @@ module Api blob = ActiveStorage::Blob.find_by!(uuid: blob_uuid) + if Submitters::DANGEROUS_EXTENSIONS.include?(blob.filename.extension.to_s.downcase) + Rollbar.error('Dangerous extension') if defined?(Rollbar) + + return head :unprocessable_content + end + attachment = blob.attachments.take @record = attachment.record @@ -46,6 +53,7 @@ module Api end end end + # rubocop:enable Metrics private diff --git a/app/controllers/api/active_storage_blobs_proxy_legacy_controller.rb b/app/controllers/api/active_storage_blobs_proxy_legacy_controller.rb index 2485b9fa..8bac4ce9 100644 --- a/app/controllers/api/active_storage_blobs_proxy_legacy_controller.rb +++ b/app/controllers/api/active_storage_blobs_proxy_legacy_controller.rb @@ -19,6 +19,12 @@ module Api return head :not_found unless blob + if Submitters::DANGEROUS_EXTENSIONS.include?(blob.filename.extension.to_s.downcase) + Rollbar.error('Dangerous extension') if defined?(Rollbar) + + return head :unprocessable_content + end + is_permitted = blob.attachments.any? do |a| (current_user && a.record.account.id == current_user.account_id) || a.record.account.account_configs.any? { |e| e.key == 'legacy_blob_proxy' } || diff --git a/app/controllers/user_initials_controller.rb b/app/controllers/user_initials_controller.rb index b2db409b..f6b87daa 100644 --- a/app/controllers/user_initials_controller.rb +++ b/app/controllers/user_initials_controller.rb @@ -11,6 +11,12 @@ class UserInitialsController < ApplicationController return redirect_to settings_profile_index_path, notice: I18n.t('unable_to_save_initials') if file.blank? + extension = File.extname(file.original_filename).delete_prefix('.').downcase + + if Submitters::DANGEROUS_EXTENSIONS.include?(extension) + raise Submitters::MaliciousFileExtension, "File type '.#{extension}' is not allowed." + end + blob = ActiveStorage::Blob.create_and_upload!(io: file.open, filename: file.original_filename, content_type: file.content_type) diff --git a/app/controllers/user_signatures_controller.rb b/app/controllers/user_signatures_controller.rb index 1200acff..f6511d00 100644 --- a/app/controllers/user_signatures_controller.rb +++ b/app/controllers/user_signatures_controller.rb @@ -11,6 +11,12 @@ class UserSignaturesController < ApplicationController return redirect_to settings_profile_index_path, notice: I18n.t('unable_to_save_signature') if file.blank? + extension = File.extname(file.original_filename).delete_prefix('.').downcase + + if Submitters::DANGEROUS_EXTENSIONS.include?(extension) + raise Submitters::MaliciousFileExtension, "File type '.#{extension}' is not allowed." + end + blob = ActiveStorage::Blob.create_and_upload!(io: file.open, filename: file.original_filename, content_type: file.content_type) diff --git a/lib/submitters/normalize_values.rb b/lib/submitters/normalize_values.rb index 61697b5f..fe9f2d02 100644 --- a/lib/submitters/normalize_values.rb +++ b/lib/submitters/normalize_values.rb @@ -212,8 +212,8 @@ module Submitters elsif type.in?(%w[signature initials]) && value.length < 60 find_or_create_blob_from_text(account, value, type) elsif (data = Base64.decode64(value.sub(BASE64_PREFIX_REGEXP, ''))) && - Marcel::MimeType.for(data).exclude?('octet-stream') - find_or_create_blob_from_base64(account, data, type) + (mime_type = Marcel::MimeType.for(data)).exclude?('octet-stream') + find_or_create_blob_from_base64(account, data, type, mime_type:) elsif type == 'image' && (value.starts_with?('') || value.starts_with?('