CVE-2022-1553: Incorrect Authorization (CWE-863)
value: Leaking password protected articles content due to improper access control in GitHub repository publify/publify prior to 9.2.8. Attackers can leverage this vulnerability to view the contents of any password-protected article present on the publify website, compromising confidentiality and integrity of users.
CWE description: The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions.
CVSS v3 base score: 4.9
Published: 2022-05-16T15:15Z
Repository: https://github.com/publify/publify
Language: Ruby
Files changed: publify_core/app/controllers/articles_controller.rb, publify_core/spec/controllers/articles_controller_spec.rb, spec/controllers/articles_controller_spec.rb
Commit date: 2022-05-14 19:24:53 +0200
Commit message: Do not create article meta description for password-protected articles

Diff: diff --git a/publify_core/app/controllers/articles_controller.rb b/publify_core/app/controllers/articles_controller.rb
index 30da1061cc..bfd12fdb87 100644
--- a/publify_core/app/controllers/articles_controller.rb
+++ b/publify_core/app/controllers/articles_controller.rb
@@ -164,11 +164,14 @@ class ArticlesController < ContentController
     auto_discovery_feed
     respond_to do |format|
       format.html do
         @comment = Comment.new
         @page_title = this_blog.article_title_template.to_title(@article, this_blog, params)
-        @description = this_blog.article_desc_template.to_title(@article, this_blog, params)
+        if @article.password.blank?
+          @description = this_blog.article_desc_template.
+            to_title(@article, this_blog, params)
+        end
 
         @keywords = @article.tags.map(&:name).join(", ")
         render "articles/#{@article.post_type}"
       end
       format.atom { render_feedback_feed("atom") }
diff --git a/publify_core/spec/controllers/articles_controller_spec.rb b/publify_core/spec/controllers/articles_controller_spec.rb
index 60b115847e..960aea3caa 100644
--- a/publify_core/spec/controllers/articles_controller_spec.rb
+++ b/publify_core/spec/controllers/articles_controller_spec.rb
@@ -481,10 +481,29 @@ RSpec.describe ArticlesController, type: :controller do
       it "does not find the article if the url does not match the fixed component" do
         expect { get :redirect, params: { from: "bar/#{article.permalink}" } }.
           to raise_error ActiveRecord::RecordNotFound
       end
     end
+
+    context "when the article is password protected" do
+      render_views
+
+      let!(:blog) { create(:blog, permalink_format: "/%title%.html") }
+      let!(:article) do
+        create(:article, title: "Secretive", body: "protected foobar", password: "password")
+      end
+
+      it "shows a password form for the article" do
+        get :redirect, params: { from: "secretive.html" }
+        expect(response.body).to have_selector('input[id="article_password"]', count: 1)
+      end
+
+      it "does not include the article body anywhere" do
+        get :redirect, params: { from: "secretive.html" }
+        expect(response.body).not_to include article.body
+      end
+    end
   end
 
   describe "#check_password" do
     render_views
     let!(:article) { create(:article, password: "password") }
diff --git a/spec/controllers/articles_controller_spec.rb b/spec/controllers/articles_controller_spec.rb
index 3c33562727..fed68d85bb 100644
--- a/spec/controllers/articles_controller_spec.rb
+++ b/spec/controllers/articles_controller_spec.rb
@@ -97,16 +97,24 @@ RSpec.describe ArticlesController, type: :controller do
             expect(response).to be_successful
           end
         end
 
         context "when the article is password protected" do
-          let(:article) { create(:article, password: "password") }
+          let(:article) do
+            create(:article, title: "Secretive", body: "protected foobar",
+                             password: "password")
+          end
 
-          it "article alone should be password protected" do
+          it "shows a password form for the article" do
             get :redirect, params: { from: from_param }
             expect(response.body).to have_selector('input[id="article_password"]', count: 1)
           end
+
+          it "does not include the article body anywhere" do
+            get :redirect, params: { from: from_param }
+            expect(response.body).not_to include article.body
+          end
         end
       end
 
       describe "#index" do
         let!(:user) { create :user }

Vulnerable code:         @description = this_blog.article_desc_template.to_title(@article, this_blog, params)
          let(:article) { create(:article, password: "password") }
          it "article alone should be password protected" do
Fixed code:         if @article.password.blank?
          @description = this_blog.article_desc_template.
            to_title(@article, this_blog, params)
        end

    context "when the article is password protected" do
      render_views

      let!(:blog) { create(:blog, permalink_format: "/%title%.html") }
      let!(:article) do
        create(:article, title: "Secretive", body: "protected foobar", password: "password")
      end

      it "shows a password form for the article" do
        get :redirect, params: { from: "secretive.html" }
        expect(response.body).to have_selector('input[id="article_password"]', count: 1)
      end

      it "does not include the article body anywhere" do
        get :redirect, params: { from: "secretive.html" }
        expect(response.body).not_to include article.body
      end
    end
          let(:article) do
            create(:article, title: "Secretive", body: "protected foobar",
                             password: "password")
          end
          it "shows a password form for the article" do

          it "does not include the article body anywhere" do
            get :redirect, params: { from: from_param }
            expect(response.body).not_to include article.body
          end