diff --git a/.rubocop.yml b/.rubocop.yml
index 37956266..12a3e63b 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -29,6 +29,9 @@ Metrics/MethodLength:
Exclude:
- spec/**/*
+RSpec/AnyInstance:
+ Enabled: false
+
RSpec/ExampleLength:
Enabled: false
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 040f54d0..1eaaf0a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,10 @@
- On cama_site_check_existence, if site is unknown, use `allow_other_host: true` for redirection to main site
- Starting from Rails 7.0 a redirection to other host will raise an exception unless the `redirect_to` method is
called with the `allow_other_host: true` option
+- Set sprocket-rails version to be at least 3.5.1
+- Use MiniMime for mime types, because the MiniMagick 5.0 has no Image#mime_type
+- Reimplement the temporary uploaded file removing, wrapping it in a bl…ock to make possible overriding the block in the app initializer to use an async job
+- Sanitize name and description attrs of TermTaxonomy classes to prevent XSS attacks
## [2.7.5](https://github.com/owen2345/camaleon-cms/tree/2.7.5) (2023-11-22)
- Fix the test email for non-main sites by [brian-kephart](https://github.com/brian-kephart) in [\#1050](https://github.com/owen2345/camaleon-cms/pull/1050)
diff --git a/app/models/camaleon_cms/term_taxonomy.rb b/app/models/camaleon_cms/term_taxonomy.rb
index ba1f4fa2..24286694 100644
--- a/app/models/camaleon_cms/term_taxonomy.rb
+++ b/app/models/camaleon_cms/term_taxonomy.rb
@@ -16,6 +16,19 @@ def self.inherited(subclass)
# attr_accessible :data_options
# attr_accessible :data_metas
+ # TODO: Remove the 1st branch when support will be dropped of Rails < 7.1
+ if ::Rails::VERSION::STRING < '7.1.0'
+ before_validation(on: %i[create update]) do
+ %i[name description].each do |attr|
+ next unless new_record? || attribute_changed?(attr)
+
+ self[attr] = ActionController::Base.helpers.sanitize(__send__(attr))
+ end
+ end
+ else
+ normalizes :name, :description, with: ->(field) { ActionController::Base.helpers.sanitize(field) }
+ end
+
# callbacks
before_validation :before_validating
before_destroy :destroy_dependencies
diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb
new file mode 100644
index 00000000..ec50212f
--- /dev/null
+++ b/spec/models/category_spec.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
+
+RSpec.describe CamaleonCms::Category, type: :model do
+ before { allow_any_instance_of(described_class).to receive(:set_site) }
+
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+end
diff --git a/spec/models/nav_menu_item_spec.rb b/spec/models/nav_menu_item_spec.rb
new file mode 100644
index 00000000..fce51f38
--- /dev/null
+++ b/spec/models/nav_menu_item_spec.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
+
+RSpec.describe CamaleonCms::NavMenuItem, type: :model do
+ before { allow_any_instance_of(described_class).to receive(:update_count) }
+
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+end
diff --git a/spec/models/nav_menu_spec.rb b/spec/models/nav_menu_spec.rb
new file mode 100644
index 00000000..397b5020
--- /dev/null
+++ b/spec/models/nav_menu_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
+
+RSpec.describe CamaleonCms::NavMenu, type: :model do
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+end
diff --git a/spec/models/plugin_spec.rb b/spec/models/plugin_spec.rb
new file mode 100644
index 00000000..b620b8d9
--- /dev/null
+++ b/spec/models/plugin_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
+
+RSpec.describe CamaleonCms::Plugin, type: :model do
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+end
diff --git a/spec/models/post_tag_spec.rb b/spec/models/post_tag_spec.rb
new file mode 100644
index 00000000..910f2e7f
--- /dev/null
+++ b/spec/models/post_tag_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
+
+RSpec.describe CamaleonCms::PostTag, type: :model do
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+end
diff --git a/spec/models/post_type_spec.rb b/spec/models/post_type_spec.rb
new file mode 100644
index 00000000..869c64c9
--- /dev/null
+++ b/spec/models/post_type_spec.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
+
+RSpec.describe CamaleonCms::PostType, type: :model do
+ init_site
+
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+end
diff --git a/spec/models/site_spec.rb b/spec/models/site_spec.rb
index d76af0fd..2f301731 100644
--- a/spec/models/site_spec.rb
+++ b/spec/models/site_spec.rb
@@ -1,8 +1,11 @@
# frozen_string_literal: true
require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
RSpec.describe CamaleonCms::Site, type: :model do
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+
describe 'check metas relationships' do
let!(:site) { create(:site).decorate }
diff --git a/spec/models/term_taxonomy_spec.rb b/spec/models/term_taxonomy_spec.rb
new file mode 100644
index 00000000..3c94596e
--- /dev/null
+++ b/spec/models/term_taxonomy_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
+
+RSpec.describe CamaleonCms::TermTaxonomy, type: :model do
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+end
diff --git a/spec/models/theme_spec.rb b/spec/models/theme_spec.rb
new file mode 100644
index 00000000..7fb7eb94
--- /dev/null
+++ b/spec/models/theme_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
+
+RSpec.describe CamaleonCms::Theme, type: :model do
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+end
diff --git a/spec/models/user_role_spec.rb b/spec/models/user_role_spec.rb
new file mode 100644
index 00000000..487d56b8
--- /dev/null
+++ b/spec/models/user_role_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
+
+RSpec.describe CamaleonCms::UserRole, type: :model do
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+end
diff --git a/spec/models/widget/widget_main_spec.rb b/spec/models/widget/widget_main_spec.rb
new file mode 100644
index 00000000..1d9dc835
--- /dev/null
+++ b/spec/models/widget/widget_main_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
+
+RSpec.describe CamaleonCms::Widget::Main, type: :model do
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+end
diff --git a/spec/models/widget/widget_sidebar_spec.rb b/spec/models/widget/widget_sidebar_spec.rb
new file mode 100644
index 00000000..104f6de5
--- /dev/null
+++ b/spec/models/widget/widget_sidebar_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'shared_specs/sanitize_attrs'
+
+RSpec.describe CamaleonCms::Widget::Sidebar, type: :model do
+ it_behaves_like 'sanitize attrs', model: described_class, attrs_to_sanitize: %i[name description]
+end
diff --git a/spec/shared_specs/sanitize_attrs.rb b/spec/shared_specs/sanitize_attrs.rb
new file mode 100644
index 00000000..0bf34027
--- /dev/null
+++ b/spec/shared_specs/sanitize_attrs.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'sanitize attrs' do |model:, attrs_to_sanitize:|
+ attrs_to_sanitize.each do |attr|
+ it 'sanitizes name attribute on create' do
+ attrs_for_creation = { attr => '">' }
+ attrs_for_creation.merge!(site: @site) if defined?(@site)
+ model_instance = model.create(attrs_for_creation)
+
+ expect(model_instance.__send__(attr)).to eql('">alert(1)')
+ end
+
+ it 'sanitizes name attribute on update' do
+ attrs_for_creation = { attr => 'Legit text' }
+ attrs_for_creation.merge!(site: @site) if defined?(@site)
+ model_instance = model.create(attrs_for_creation)
+ # attrs_for_creation = { attr => '">' }
+ model_instance.update(attr => '">')
+
+ expect(model_instance.__send__(attr)).to eql('">alert(1)')
+ end
+ end
+end