Coordinated Disclosure Timeline

Summary

Lobsters contained issues allowing unauthenticated users to create new domain entries and permitting Mastodon accounts to be linked to users without proper validation.

Project

Lobsters

Tested Version

564f00b

Details

Issue 1: Missing check for linking Mastodon account to user (GHSL-2025-126)

A Cross-Site Request Forgery (CSRF) vulnerability existed in the Lobsters application’s Mastodon OAuth integration that allowed attackers to link a victim’s Lobsters account to an attacker-controlled Mastodon account without the victim’s knowledge or consent. This was possible because the OAuth callback flow lacked state parameter validation and session binding, enabling unauthorized modification of user account associations through a simple GET request. Note: Only Lobsters instances that had Mastodon linking enabled were affected by this vulnerability.

Issue: No session state is created (e.g., session[:mastodon_state] = SecureRandom.hex) and included in the URL for the OAuth instance:

def oauth_auth_url
  "https://#{name}/oauth/authorize?response_type=code&client_id=#{client_id}&scope=read:accounts&redirect_uri=#{CGI.escape(redirect_uri)}"
end

Consequently, the state cannot be validated in the mastodon_callback method:

  def mastodon_callback
    if params[:code].blank?
      flash[:error] = "Invalid OAuth state"
      return redirect_to settings_path
    end
[..]
end

Impact

This vulnerability allows attackers to link to any Mastodon profile from the Lobsters profile page of their victims. It might enable further impact should Lobsters expand the Mastodon integration.

CWEs

Resources

Issue 2: Unauthenticated users can create new domain entries (GHSL-2025-127)

An authorization bypass vulnerability existed in Lobsters that allowed unauthenticated users to create Domain records via the POST /domains endpoint. The vulnerability can lead to data pollution and potentially the disruption of moderation workflows. Attackers might use it to (partially) disguise a spam/phishing domain as a trusted domain.

The vulnerability stems from inconsistent application of authorization checks in the DomainsController. While the :edit and :update actions are protected with before_action :require_logged_in_moderator, the :create action lacks any authentication or authorization requirement.

Relevant Code Locations

1. Route Definition (config/routes.rb:75)

resources :domains, only: [:create, :edit, :update]

Exposes POST /domains for the create action without restrictions.

2. Controller Authorization (app/controllers/domains_controller.rb:3-6)

before_action :require_logged_in_moderator, only: [:edit, :update]

The before_action filter only applies to :edit and :update, explicitly excluding :create.

3. Unprotected Create Action (app/controllers/domains_controller.rb:7-18)

def create
  @domain = Domain.where(:domain => params[:new_domain]).first_or_initialize
  # ... no authorization check ...
  @domain.save
end

4. Permitted Parameters (app/controllers/domains_controller.rb:35-36)

params.require(:domain).permit(:banned_reason, :selector, :replacement)

Impact

The vulnerability can lead to data pollution and potentially the disruption of moderation workflows. Attackers might use this vulnerability to disguise a malicious domain as a trusted domain.

CWEs

Credit

This issue was discovered with the GitHub Security Lab Taskflow Agent and manually verified by GHSL team members @p- (Peter Stöckli) and @m-y-mo (Man Yue Mo).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2025-126 or GHSL-2025-127 in any communication regarding these issues.