VYPR
High severityNVD Advisory· Published Sep 18, 2024· Updated Apr 17, 2025

Arbitrary path traversal in Camaleon CMS

CVE-2024-46987

Description

Camaleon CMS is a dynamic and advanced content management system based on Ruby on Rails. A path traversal vulnerability accessible via MediaController's download_private_file method allows authenticated users to download any file on the web server Camaleon CMS is running on (depending on the file permissions). This issue may lead to Information Disclosure. This issue has been addressed in release version 2.8.2. Users are advised to upgrade. There are no known workarounds for this vulnerability.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
camaleon_cmsRubyGems
< 2.8.12.8.1

Affected products

1

Patches

1
071b1b09d6d6

Merge pull request #1083 from texpert/fix-path-traversal-in-download-private-file

https://github.com/owen2345/camaleon-cmsAurel BranzeanuAug 13, 2024via ghsa
7 files changed · +65 8
  • app/controllers/camaleon_cms/admin/media_controller.rb+2 0 modified
    @@ -30,6 +30,8 @@ def download_private_file
     
             file = cama_uploader.fetch_file("private/#{params[:file]}")
     
    +        return render plain: helpers.sanitize(file[:error]) if file.is_a?(Hash) && file[:error].present?
    +
             send_file file, disposition: 'inline'
           end
     
    
  • app/uploaders/camaleon_cms_aws_uploader.rb+3 3 modified
    @@ -36,11 +36,11 @@ def objects(prefix = '/', sort = 'created_at')
       end
     
       def fetch_file(file_name)
    -    bucket.object(file_name).download_file(file_name) unless file_exists?(file_name)
    +    return file_name if file_exists?(file_name)
     
    -    raise ActionController::RoutingError, 'File not found' unless file_exists?(file_name)
    +    return file_name if bucket.object(file_name).download_file(file_name) && file_exists?(file_name)
     
    -    file_name
    +    { error: 'File not found' }
       end
     
       # parse an AWS file into custom file_object
    
  • app/uploaders/camaleon_cms_local_uploader.rb+4 2 modified
    @@ -25,9 +25,11 @@ def browser_files(prefix = '/', _objects = {})
       end
     
       def fetch_file(file_name)
    -    raise ActionController::RoutingError, 'File not found' unless file_exists?(file_name)
    +    return { error: 'Invalid file path' } if file_name.include?('..')
     
    -    file_name
    +    return file_name if file_exists?(file_name)
    +
    +    { error: 'File not found' }
       end
     
       def file_parse(key)
    
  • CHANGELOG.md+2 0 modified
    @@ -8,6 +8,8 @@
     - **Security fix:** Mitigate arbitrary path write in uploader (GHSL-2024-182)
       - Thanks [Peter Stöckli](https://github.com/p-) for reporting and providing clear reproduction steps
     - Add Rails 7.2 to stable testing on CI, point rails_edge to main branch
    +- **Security fix:** Mitigate arbitrary path traversal in download_private_file (GHSL-2024-183)
    +  - Thanks [Peter Stöckli](https://github.com/p-) for reporting and providing clear reproduction steps
     
     ## [2.8.0](https://github.com/owen2345/camaleon-cms/tree/2.8.0) (2024-07-26)
     - Use jQuery 2.x - 2.2.4
    
  • Gemfile+2 2 modified
    @@ -1,9 +1,9 @@
     source 'https://rubygems.org'
     
     gemspec
    -gem 'non-digest-assets'
    +gem 'non-digest-assets', git: 'https://github.com/mvz/non-digest-assets'
     gem 'oj'
    -gem 'rails', '~> 7.1.0'
    +gem 'rails', '~> 7.2.0'
     gem 'selenium-webdriver'
     gem 'sprockets-rails', '>= 3.5.1'
     
    
  • spec/dummy/config/environments/test.rb+5 1 modified
    @@ -25,7 +25,11 @@
       config.assets.check_precompiled_asset = false
     
       # Raise exceptions instead of rendering exception templates.
    -  config.action_dispatch.show_exceptions = false
    +  config.action_dispatch.show_exceptions = if ::Rails::VERSION::STRING < '7.2.0'
    +                                             false
    +                                           else
    +                                             :none
    +                                           end
     
       # Disable request forgery protection in test environment.
       config.action_controller.allow_forgery_protection = false
    
  • spec/requests/download_private_file_spec.rb+47 0 added
    @@ -0,0 +1,47 @@
    +# frozen_string_literal: true
    +
    +require 'rails_helper'
    +
    +RSpec.describe 'Media requests', type: :request do
    +  init_site
    +
    +  describe 'Download private file' do
    +    let(:current_site) { Cama::Site.first.decorate }
    +
    +    before do
    +      allow_any_instance_of(CamaleonCms::Admin::MediaController).to receive(:cama_authenticate)
    +      allow_any_instance_of(CamaleonCms::Admin::MediaController).to receive(:current_site).and_return(current_site)
    +    end
    +
    +    context 'when the file path is valid and file exists' do
    +      before do
    +        allow_any_instance_of(CamaleonCmsLocalUploader).to receive(:fetch_file).and_return('some_file')
    +
    +        allow_any_instance_of(CamaleonCms::Admin::MediaController).to receive(:send_file)
    +        allow_any_instance_of(CamaleonCms::Admin::MediaController).to receive(:default_render)
    +      end
    +
    +      it 'allows the file to be downloaded' do
    +        expect_any_instance_of(CamaleonCms::Admin::MediaController).to receive(:send_file).with('some_file', disposition: 'inline')
    +
    +        get '/admin/media/download_private_file', params: { file: 'some_file' }
    +      end
    +    end
    +
    +    context 'when file path is invalid' do
    +      it 'returns invalid file path error' do
    +        get '/admin/media/download_private_file', params: { file: './../../../../../etc/passwd' }
    +
    +        expect(response.body).to include('Invalid file path')
    +      end
    +    end
    +
    +    context 'when the file is not found' do
    +      it 'returns file not found error' do
    +        get '/admin/media/download_private_file', params: { file: 'passwd' }
    +
    +        expect(response.body).to include('File not found')
    +      end
    +    end
    +  end
    +end
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

9

News mentions

1