carrierwaveuploader/carrierwave · error · CarrierWave::IntegrityError

errors.messages.content_type_denylist_error

Error message

errors.messages.content_type_denylist_error

What it means

Raised as CarrierWave::IntegrityError when check_content_type_denylist! finds the uploaded file's content type matches an entry in the deprecated content_type_denylist (matching is unanchored regex: content_type =~ /#{item}/). Note the method itself warns that denylisting is deprecated for security reasons and recommends content_type_allowlist; it also still honors the older content_type_blacklist with a warning.

Source

Thrown at lib/carrierwave/uploader/content_type_denylist.rb:51

    private

      def check_content_type_denylist!(new_file)
        denylist = content_type_denylist
        if !denylist && respond_to?(:content_type_blacklist) && content_type_blacklist
          CarrierWave.deprecator.warn "#content_type_blacklist is deprecated, use #content_type_denylist instead." unless instance_variable_defined?(:@content_type_blacklist_warned)
          @content_type_blacklist_warned = true
          denylist = content_type_blacklist
        end

        return unless denylist

        CarrierWave.deprecator.warn "Use of #content_type_denylist is deprecated for the security reason, use #content_type_allowlist instead to explicitly state what are safe to accept" unless instance_variable_defined?(:@content_type_denylist_warned)
        @content_type_denylist_warned = true

        content_type = new_file.content_type
        if denylisted_content_type?(denylist, content_type)
          raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_denylist_error",
                                                            content_type: content_type, default: :"errors.messages.content_type_blacklist_error")
        end
      end

      def denylisted_content_type?(denylist, content_type)
        Array(denylist).any? do |item|
          item = Regexp.quote(item) if item.class != Regexp
          content_type =~ /#{item}/
        end
      end

    end # ContentTypeDenylist
  end # Uploader
end # CarrierWave

View on GitHub (pinned to b5f0abe10e)

Solutions

  1. Replace content_type_denylist with an explicit content_type_allowlist of the types you actually accept
  2. Rescue CarrierWave::IntegrityError and render a validation message instead of a 500
  3. If you must temporarily keep the denylist, remember matching is substring-based — anchor regexes deliberately

Example fix

# before
class DocUploader < CarrierWave::Uploader::Base
  def content_type_denylist; ['application/x-msdownload']; end # IntegrityError + deprecation
end

# after
class DocUploader < CarrierWave::Uploader::Base
  def content_type_allowlist; %w(application/pdf image/png); end
end
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = %w[application/pdf image/png].freeze

def content_type_allowed?(type)
  ALLOWED.any? { |a| type.to_s.start_with?(a) }
end

Type guard

def content_type_allowed?(type)
  ALLOWED.any? { |a| type.to_s.start_with?(a) }
end

Try / catch

begin
  record.doc = params[:doc]
  record.save!
rescue CarrierWave::IntegrityError
  record.errors.add(:doc, :content_type_not_allowed)
  render :new
end

Prevention

When it happens

Trigger: Declaring content_type_denylist ['text/html', 'application/php'] and uploading a file whose reported type matches any entry as a substring; or still defining content_type_blacklist from pre-migration code, which routes into the same check.

Common situations: Apps migrated from old whitelist/blacklist-named methods that kept the blacklist semantics; security reviews flagging that content types can be spoofed client-side, since denylisting trusts the browser-reported type.

Related errors


AI-assisted analysis of carrierwaveuploader/carrierwave@b5f0abe10e (2026-08-21). Data as JSON: /api/errors/49c8df5067ac130a. Report an issue: GitHub.