VYPR
Medium severity6.5NVD Advisory· Published Jun 12, 2026

CVE-2026-44784

CVE-2026-44784

Description

Discourse group owners who are not admins or moderators can view SMTP credentials in plaintext via the group history log, allowing unauthorized email sending as the group.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Discourse group owners who are not admins or moderators can view SMTP credentials in plaintext via the group history log, allowing unauthorized email sending as the group.

Vulnerability

In Discourse versions 2026.1.0 to before 2026.1.4, 2026.3.0 to before 2026.3.1, and 2026.4.0 to before 2026.4.1, group owners who are not necessarily admins or moderators can view a group's outgoing email/SMTP credentials in plaintext via the group history log endpoint (/groups/:name/logs.json). The affected fields include email_password, email_username, smtp_server, smtp_port, and smtp_ssl_mode. This issue impacts sites that have configured per-group SMTP credentials and granted group ownership to users who should not have access to those credentials [1].

Exploitation

An attacker who is a group owner of a group with per-group SMTP credentials can access the group history log at /groups/:name/logs.json to view the plaintext SMTP password and other credentials. No additional privileges are required beyond being a group owner [1].

Impact

Successful exploitation exposes the SMTP password, which the attacker can use to send email as the group from outside Discourse. This enables impersonation, phishing attacks, or other malicious email campaigns originating from the compromised group's identity [1].

Mitigation

The vulnerability has been patched in Discourse versions 2026.1.4, 2026.3.1, 2026.4.1, and 2026.5.0-latest.1. As workarounds, administrators can either remove non-admin group owners from groups that have email/SMTP credentials configured, or clear the email password (and rotate it on the upstream mail provider) on any group where non-admin owners exist [1].

AI Insight generated on Jun 12, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2
  • >=2026.1.0,<2026.1.4 || >=2026.3.0,<2026.3.1 || >=2026.4.0,<2026.4.1+ 1 more
    • (no CPE)range: >=2026.1.0,<2026.1.4 || >=2026.3.0,<2026.3.1 || >=2026.4.0,<2026.4.1
    • (no CPE)range: >= 2026.1.0, < 2026.1.4 || >= 2026.3.0, < 2026.3.1 || >= 2026.4.0, < 2026.4.1

Patches

3
cacb6c1821b8

SECURITY: Redact group history related to email password to group owners [backport 2026.4]

https://github.com/discourse/discourseNatMay 18, 2026Fixed in 2026.4.1via llm-release-walk
2 files changed · +44 0
  • app/serializers/basic_group_history_serializer.rb+21 0 modified
    @@ -1,6 +1,9 @@
     # frozen_string_literal: true
     
     class BasicGroupHistorySerializer < ApplicationSerializer
    +  EMAIL_SETTING_SUBJECTS =
    +    Set.new(%w[email_password email_username smtp_server smtp_port smtp_ssl_mode])
    +
       attributes :action, :subject, :prev_value, :new_value, :created_at
     
       has_one :acting_user, embed: :objects, serializer: BasicUserSerializer
    @@ -9,4 +12,22 @@ class BasicGroupHistorySerializer < ApplicationSerializer
       def action
         GroupHistory.actions[object.action]
       end
    +
    +  def prev_value
    +    redact_email_setting_value(object.prev_value)
    +  end
    +
    +  def new_value
    +    redact_email_setting_value(object.new_value)
    +  end
    +
    +  private
    +
    +  def redact_email_setting_value(value)
    +    return value if value.blank?
    +    return value if !EMAIL_SETTING_SUBJECTS.include?(object.subject)
    +    return value if scope&.can_admin_group?(object.group)
    +
    +    I18n.t("staff_action_logs.redacted")
    +  end
     end
    
  • spec/requests/groups_controller_spec.rb+23 0 modified
    @@ -2535,6 +2535,29 @@ def expect_type_to_return_right_groups(type, expected_group_ids)
             end
           end
     
    +      it "does not expose email setting values in history logs" do
    +        group.update!(
    +          email_password: "secret_smtp_pass",
    +          email_username: "group@example.com",
    +          smtp_server: "smtp.example.com",
    +          smtp_port: 587,
    +          smtp_ssl_mode: "starttls",
    +        )
    +        GroupActionLogger.new(admin, group).log_change_group_settings
    +
    +        get "/groups/#{group.name}/logs.json"
    +
    +        expect(response.status).to eq(200)
    +
    +        logs = response.parsed_body["logs"]
    +        redacted = I18n.t("staff_action_logs.redacted")
    +
    +        %w[email_password email_username smtp_server smtp_port smtp_ssl_mode].each do |subject|
    +          entry = logs.find { |log| log["subject"] == subject }
    +          expect(entry["new_value"]).to eq(redacted)
    +        end
    +      end
    +
           it "should not be allowed to view history of an automatic group" do
             group = Group.find_by(id: Group::AUTO_GROUPS[:admins])
     
    
b627ef593fc5

SECURITY: Redact group history related to email password to group owners [backport 2026.3]

https://github.com/discourse/discourseNatMay 18, 2026Fixed in 2026.3.1via llm-release-walk
2 files changed · +44 0
  • app/serializers/basic_group_history_serializer.rb+21 0 modified
    @@ -1,6 +1,9 @@
     # frozen_string_literal: true
     
     class BasicGroupHistorySerializer < ApplicationSerializer
    +  EMAIL_SETTING_SUBJECTS =
    +    Set.new(%w[email_password email_username smtp_server smtp_port smtp_ssl_mode])
    +
       attributes :action, :subject, :prev_value, :new_value, :created_at
     
       has_one :acting_user, embed: :objects, serializer: BasicUserSerializer
    @@ -9,4 +12,22 @@ class BasicGroupHistorySerializer < ApplicationSerializer
       def action
         GroupHistory.actions[object.action]
       end
    +
    +  def prev_value
    +    redact_email_setting_value(object.prev_value)
    +  end
    +
    +  def new_value
    +    redact_email_setting_value(object.new_value)
    +  end
    +
    +  private
    +
    +  def redact_email_setting_value(value)
    +    return value if value.blank?
    +    return value if !EMAIL_SETTING_SUBJECTS.include?(object.subject)
    +    return value if scope&.can_admin_group?(object.group)
    +
    +    I18n.t("staff_action_logs.redacted")
    +  end
     end
    
  • spec/requests/groups_controller_spec.rb+23 0 modified
    @@ -2470,6 +2470,29 @@ def expect_type_to_return_right_groups(type, expected_group_ids)
             end
           end
     
    +      it "does not expose email setting values in history logs" do
    +        group.update!(
    +          email_password: "secret_smtp_pass",
    +          email_username: "group@example.com",
    +          smtp_server: "smtp.example.com",
    +          smtp_port: 587,
    +          smtp_ssl_mode: "starttls",
    +        )
    +        GroupActionLogger.new(admin, group).log_change_group_settings
    +
    +        get "/groups/#{group.name}/logs.json"
    +
    +        expect(response.status).to eq(200)
    +
    +        logs = response.parsed_body["logs"]
    +        redacted = I18n.t("staff_action_logs.redacted")
    +
    +        %w[email_password email_username smtp_server smtp_port smtp_ssl_mode].each do |subject|
    +          entry = logs.find { |log| log["subject"] == subject }
    +          expect(entry["new_value"]).to eq(redacted)
    +        end
    +      end
    +
           it "should not be allowed to view history of an automatic group" do
             group = Group.find_by(id: Group::AUTO_GROUPS[:admins])
     
    
5e4e299fa937

SECURITY: Redact group history related to email password to group owners [backport 2026.1]

https://github.com/discourse/discourseNatMay 18, 2026Fixed in 2026.1.4via llm-release-walk
2 files changed · +44 0
  • app/serializers/basic_group_history_serializer.rb+21 0 modified
    @@ -1,6 +1,9 @@
     # frozen_string_literal: true
     
     class BasicGroupHistorySerializer < ApplicationSerializer
    +  EMAIL_SETTING_SUBJECTS =
    +    Set.new(%w[email_password email_username smtp_server smtp_port smtp_ssl_mode])
    +
       attributes :action, :subject, :prev_value, :new_value, :created_at
     
       has_one :acting_user, embed: :objects, serializer: BasicUserSerializer
    @@ -9,4 +12,22 @@ class BasicGroupHistorySerializer < ApplicationSerializer
       def action
         GroupHistory.actions[object.action]
       end
    +
    +  def prev_value
    +    redact_email_setting_value(object.prev_value)
    +  end
    +
    +  def new_value
    +    redact_email_setting_value(object.new_value)
    +  end
    +
    +  private
    +
    +  def redact_email_setting_value(value)
    +    return value if value.blank?
    +    return value if !EMAIL_SETTING_SUBJECTS.include?(object.subject)
    +    return value if scope&.can_admin_group?(object.group)
    +
    +    I18n.t("staff_action_logs.redacted")
    +  end
     end
    
  • spec/requests/groups_controller_spec.rb+23 0 modified
    @@ -2436,6 +2436,29 @@ def expect_type_to_return_right_groups(type, expected_group_ids)
             end
           end
     
    +      it "does not expose email setting values in history logs" do
    +        group.update!(
    +          email_password: "secret_smtp_pass",
    +          email_username: "group@example.com",
    +          smtp_server: "smtp.example.com",
    +          smtp_port: 587,
    +          smtp_ssl_mode: "starttls",
    +        )
    +        GroupActionLogger.new(admin, group).log_change_group_settings
    +
    +        get "/groups/#{group.name}/logs.json"
    +
    +        expect(response.status).to eq(200)
    +
    +        logs = response.parsed_body["logs"]
    +        redacted = I18n.t("staff_action_logs.redacted")
    +
    +        %w[email_password email_username smtp_server smtp_port smtp_ssl_mode].each do |subject|
    +          entry = logs.find { |log| log["subject"] == subject }
    +          expect(entry["new_value"]).to eq(redacted)
    +        end
    +      end
    +
           it "should not be allowed to view history of an automatic group" do
             group = Group.find_by(id: Group::AUTO_GROUPS[:admins])
     
    

Vulnerability mechanics

Root cause

"Missing authorization check in the group history serializer allows non-admin group owners to view SMTP credentials in plaintext."

Attack vector

An attacker who is a group owner (but not an admin or moderator) can view the group's SMTP credentials—email_password, email_username, smtp_server, smtp_port, smtp_ssl_mode—by making a GET request to `/groups/:name/logs.json` and inspecting the `new_value` or `prev_value` fields for those subjects. No special authentication beyond being a group owner is needed, and the request is made over the network to the public-facing Discourse endpoint. The SMTP password (`email_password`) could then be used outside Discourse to send mail as the group.

Affected code

The vulnerability lies in `app/serializers/basic_group_history_serializer.rb`. The `prev_value` and `new_value` attributes were previously returned without redaction, allowing any user who can view the group history log (including group owners) to see SMTP credentials in plaintext. The patch adds a `redact_email_setting_value` method that checks the `subject` against `EMAIL_SETTING_SUBJECTS` and only returns the original value if the requester can `admin` the group (i.e., is an admin or moderator).

What the fix does

The patch introduces a constant `EMAIL_SETTING_SUBJECTS` listing the sensitive fields (`email_password`, `email_username`, `smtp_server`, `smtp_port`, `smtp_ssl_mode`), and a private method `redact_email_setting_value` in `BasicGroupHistorySerializer`. When serializing `prev_value` or `new_value`, the method checks whether the subject is in that set and whether the requesting user `can_admin_group?(object.group)`. If the user lacks admin rights (which group owners do), the value is replaced with the I18n translation `"staff_action_logs.redacted"` instead of the plaintext credential.

Preconditions

  • authThe attacker must be a group owner on a site that has per-group SMTP credentials configured.
  • networkThe attacker must have network access to the Discourse instance.
  • configThe target group must have at least one SMTP setting changed and logged in its history.

Generated on Jun 12, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

1

News mentions

0

No linked articles in our index yet.