SECURITY: Limit ThemeField value length to prevent DoS (#22087)

Co-authored-by: Daniel Waterworth <me@danielwaterworth.com>
This commit is contained in:
Blake Erickson 2023-06-13 11:07:47 -06:00 committed by GitHub
parent e576fdbe3a
commit 56b74e6042
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 1 deletions

View File

@ -14,7 +14,7 @@ class Theme < ActiveRecord::Base
belongs_to :user
belongs_to :color_scheme
has_many :theme_fields, dependent: :destroy
has_many :theme_fields, dependent: :destroy, validate: false
has_many :theme_settings, dependent: :destroy
has_many :theme_translation_overrides, dependent: :destroy
has_many :child_theme_relation,
@ -59,6 +59,7 @@ class Theme < ActiveRecord::Base
class_name: "ThemeField"
validate :component_validations
validate :validate_theme_fields
after_create :update_child_components
@ -300,6 +301,12 @@ class Theme < ActiveRecord::Base
errors.add(:base, I18n.t("themes.errors.component_no_default")) if default?
end
def validate_theme_fields
theme_fields.each do |field|
field.errors.full_messages.each { |message| errors.add(:base, message) } unless field.valid?
end
end
def switch_to_component!
return if component

View File

@ -5,6 +5,8 @@ class ThemeField < ActiveRecord::Base
has_one :javascript_cache, dependent: :destroy
has_one :upload_reference, as: :target, dependent: :destroy
validates :value, { length: { maximum: 1024**2 } }
after_save do
if self.type_id == ThemeField.types[:theme_upload_var] && saved_change_to_upload_id?
UploadReference.ensure_exist!(upload_ids: [self.upload_id], target: self)

View File

@ -668,6 +668,42 @@ RSpec.describe Admin::ThemesController do
expect(response.status).to eq(403)
end
it "creates new theme fields" do
expect(theme.theme_fields.count).to eq(0)
put "/admin/themes/#{theme.id}.json",
params: {
theme: {
theme_fields: [{ name: "scss", target: "common", value: "test" }],
},
}
expect(response.status).to eq(200)
theme.reload
expect(theme.theme_fields.count).to eq(1)
theme_field = theme.theme_fields.first
expect(theme_field.name).to eq("scss")
expect(theme_field.target_id).to eq(Theme.targets[:common])
expect(theme_field.value).to eq("test")
end
it "doesn't create theme fields when they don't pass validation" do
expect(theme.theme_fields.count).to eq(0)
put "/admin/themes/#{theme.id}.json",
params: {
theme: {
theme_fields: [
{ name: "scss", target: "common", value: "Na " * 1024**2 + "Batman!" },
],
},
}
expect(response.status).to eq(422)
json = JSON.parse(response.body)
expect(json["errors"].first).to include("Value is too long")
end
it "allows zip-imported theme fields to be locally edited" do
r = RemoteTheme.create!(remote_url: "")
theme.update!(remote_theme_id: r.id)