From a747724cb6135b176d1aa78571787bdf15307936 Mon Sep 17 00:00:00 2001 From: Vinoth Kannan Date: Thu, 30 May 2024 06:32:57 +0530 Subject: [PATCH] SECURITY: limit the number of characters in watched word replacements. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The watch words controller creation function, create_or_update_word(), doesn’t validate the size of the replacement parameter, unlike the word parameter, when creating a replace watched word. So anyone with moderator privileges can create watched words with almost unlimited characters. --- app/models/watched_word.rb | 6 +++++- spec/models/watched_word_spec.rb | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/models/watched_word.rb b/app/models/watched_word.rb index 0ceccd5272d..319c874e1fd 100644 --- a/app/models/watched_word.rb +++ b/app/models/watched_word.rb @@ -3,7 +3,10 @@ class WatchedWord < ActiveRecord::Base MAX_WORDS_PER_ACTION = 2000 - before_validation { self.word = WatchedWord.normalize_word(self.word) } + before_validation do + self.word = WatchedWord.normalize_word(self.word) + self.replacement = WatchedWord.normalize_word(self.replacement) if self.replacement.present? + end before_validation do if self.action == WatchedWord.actions[:link] && self.replacement !~ %r{\Ahttps?://} @@ -13,6 +16,7 @@ class WatchedWord < ActiveRecord::Base end validates :word, presence: true, uniqueness: true, length: { maximum: 100 } + validates :replacement, length: { maximum: 100 } validates :action, presence: true validate :replacement_is_url, if: -> { action == WatchedWord.actions[:link] } validate :replacement_is_tag_list, if: -> { action == WatchedWord.actions[:tag] } diff --git a/spec/models/watched_word_spec.rb b/spec/models/watched_word_spec.rb index 16b992a157e..7e0415b8f84 100644 --- a/spec/models/watched_word_spec.rb +++ b/spec/models/watched_word_spec.rb @@ -26,6 +26,18 @@ RSpec.describe WatchedWord do expect(described_class.create(word: "Jest").case_sensitive?).to eq(false) end + it "limits the number of characters in a word" do + w = Fabricate.build(:watched_word, word: "a" * 101) + expect(w).to_not be_valid + expect(w.errors[:word]).to be_present + end + + it "limits the number of characters in a replacement" do + w = Fabricate.build(:watched_word, replacement: "a" * 101) + expect(w).to_not be_valid + expect(w.errors[:replacement]).to be_present + end + describe "action_key=" do let(:w) { WatchedWord.new(word: "troll") }