VYPR
High severity7.5NVD Advisory· Published Jun 15, 2026

CVE-2026-47777

CVE-2026-47777

Description

Missing origin check in Mastodon's remote Collection consent verification lets attackers forge FeatureAuthorization to falsely include accounts.

AI Insight

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

Missing origin check in Mastodon's remote Collection consent verification lets attackers forge FeatureAuthorization to falsely include accounts.

Vulnerability

Mastodon, an open-source ActivityPub social network server (versions prior to 4.6.0-beta.1 on the main branch or nightly builds with EXPERIMENTAL_FEATURES including collections), fails to verify that the featureAuthorization object in a collection item references the same featuredObject as the item itself. The non_matching_uri_hosts? check was missing for the actor and approval URIs, allowing a forged authorization residing on the same domain as a different object to pass validation [1], [2].

Exploitation

An attacker must control a remote ActivityPub server capable of serving a forged FeatureAuthorization object. The attacker crafts a collection item where the featureAuthorization URI points to a legitimate authorization for a different object on the same domain, while the actual featuredObject is not authorized. The missing comparison between featuredObject and featureAuthorization's target allows the check to pass [1], [2].

Impact

A successful attack bypasses consent verification, making it appear that a remote account has consented to be featured in a Collection when it has not. The attacker can falsely include accounts in collections, violating user consent expectations, but does not lead to direct data disclosure, code execution, or privilege escalation [2].

Mitigation

The fix is included in commit 22203f8, which adds a non_matching_actor_and_approval_uris? check to ensure the featuredObject matches the featureAuthorization's target [1]. This is present in nightly images from nightly.2026-05-21-security onward and will be part of the stable release 4.6.0-beta.1 [2]. Servers not using the experimental EXPERIMENTAL_FEATURES=collections are unaffected. No workaround is available for affected builds; administrators should update to a patched version or disable the experimental feature [2].

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

Affected products

2
  • Mastodon/Mastodonreferences2 versions
    (expand)+ 1 more
    • (no CPE)
    • (no CPE)range: >= 4.6.0-beta.1

Patches

1
22203f8aeb03

Improve collection item verification (#39096)

https://github.com/mastodon/mastodonDavid RoetzelMay 20, 2026via nvd-ref
4 files changed · +51 5
  • app/services/activitypub/process_featured_item_service.rb+9 2 modified
    @@ -11,7 +11,10 @@ def call(collection, uri_or_object, position: nil, request_id: nil)
         @collection = collection
         @request_id = request_id
         @item_json = uri_or_object.is_a?(String) ? fetch_resource(uri_or_object, true) : uri_or_object
    +    @actor_uri = value_or_id(@item_json['featuredObject'])
    +    @approval_uri = value_or_id(@item_json['featureAuthorization'])
         return if non_matching_uri_hosts?(@collection.uri, @item_json['id'])
    +    return if non_matching_actor_and_approval_uris?
     
         with_redis_lock("collection_item:#{@item_json['id']}") do
           @collection_item = existing_item || pre_approved_item || new_item
    @@ -22,8 +25,6 @@ def call(collection, uri_or_object, position: nil, request_id: nil)
             object_uri: value_or_id(@item_json['featuredObject'])
           )
     
    -      @approval_uri = @item_json['featureAuthorization']
    -
           verify_authorization! unless @collection_item&.account&.local?
     
           @collection_item
    @@ -48,6 +49,12 @@ def new_item
         )
       end
     
    +  def non_matching_actor_and_approval_uris?
    +    return false if ActivityPub::TagManager.instance.local_uri?(@actor_uri)
    +
    +    non_matching_uri_hosts?(@actor_uri, @approval_uri)
    +  end
    +
       def verify_authorization!
         ActivityPub::VerifyFeaturedItemService.new.call(@collection_item, @approval_uri, request_id: @request_id)
       rescue Mastodon::RecursionLimitExceededError, Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
    
  • app/services/activitypub/verify_featured_item_service.rb+10 3 modified
    @@ -12,8 +12,11 @@ def call(collection_item, approval_uri, request_id: nil)
           return
         end
     
    -    return if non_matching_uri_hosts?(approval_uri, @authorization['interactionTarget'])
    -    return unless matching_type? && matching_collection_uri?
    +    @collection_uri = value_or_id(@authorization['interactingObject'])
    +    @actor_uri = value_or_id(@authorization['interactionTarget'])
    +
    +    return if non_matching_uri_hosts?(approval_uri, @actor_uri)
    +    return unless matching_type? && matching_collection_uri? && matching_actors?
     
         account = Account.where(uri: @collection_item.object_uri).first
         account ||= ActivityPub::FetchRemoteAccountService.new.call(@collection_item.object_uri, request_id:)
    @@ -29,6 +32,10 @@ def matching_type?
       end
     
       def matching_collection_uri?
    -    @collection_item.collection.uri == @authorization['interactingObject']
    +    @collection_item.collection.uri == @collection_uri
    +  end
    +
    +  def matching_actors?
    +    @collection_item.object_uri == @actor_uri
       end
     end
    
  • spec/services/activitypub/process_featured_item_service_spec.rb+11 0 modified
    @@ -40,6 +40,17 @@
             end.to_not change(CollectionItem, :count)
           end
         end
    +
    +    context 'when the actor URI does not match the approval URI' do
    +      let(:featured_object_uri) { 'https://example.com/actor/1' }
    +      let(:feature_authorization_uri) { 'https://other.example.com/auth/1' }
    +
    +      it 'does not create a collection item and returns `nil`' do
    +        expect do
    +          expect(subject.call(collection, object, position:)).to be_nil
    +        end.to_not change(CollectionItem, :count)
    +      end
    +    end
       end
     
       context 'when the collection item is inlined' do
    
  • spec/services/activitypub/verify_featured_item_service_spec.rb+21 0 modified
    @@ -85,4 +85,25 @@
           expect(collection_item).to be_rejected
         end
       end
    +
    +  context 'when the authorization references a different account' do
    +    let(:verification_json) do
    +      {
    +        '@context' => 'https://www.w3.org/ns/activitystreams',
    +        'type' => 'FeatureAuthorization',
    +        'id' => approval_uri,
    +        'interactionTarget' => 'https://example.com/actor/2',
    +        'interactingObject' => collection.uri,
    +      }
    +    end
    +
    +    before { featured_account }
    +
    +    it 'does not verify the item' do
    +      subject.call(collection_item, approval_uri)
    +
    +      expect(collection_item.account_id).to be_nil
    +      expect(collection_item).to be_pending
    +    end
    +  end
     end
    

Vulnerability mechanics

Root cause

"Missing verification that the `FeatureAuthorization` object's `interactionTarget` matches the collection item's `object_uri`, allowing an attacker to forge consent for a different account."

Attack vector

An attacker can forge a `FeatureAuthorization` object that resides on the same domain as the target object but references a different account than the one actually featured in the Collection. Because the missing `matching_actors?` check in `VerifyFeaturedItemService` [patch_id=6086852] did not confirm that the `interactionTarget` matches the collection item's `object_uri`, the forged authorization would be accepted. This allows the attacker to make it appear as if a remote account consented to being featured when it did not. The attack is network-based, requires no authentication, and only affects servers that have enabled the experimental Collections feature.

Affected code

The vulnerability resides in `app/services/activitypub/process_featured_item_service.rb` and `app/services/activitypub/verify_featured_item_service.rb`. The `process_featured_item_service` lacked a check that the actor URI and the approval URI belong to the same host, and `verify_featured_item_service` did not verify that the `interactionTarget` of the `FeatureAuthorization` matches the `object_uri` of the collection item being verified.

What the fix does

The patch adds two new checks. In `ProcessFeaturedItemService`, a new `non_matching_actor_and_approval_uris?` method ensures that the actor URI and the approval URI share the same host (unless the actor is local). In `VerifyFeaturedItemService`, a new `matching_actors?` method verifies that the `interactionTarget` of the `FeatureAuthorization` matches the `object_uri` of the collection item. Together these prevent an attacker from using a `FeatureAuthorization` that was issued for a different account to falsely authorize a collection item.

Preconditions

  • configThe Mastodon server must have the experimental Collections feature enabled via the `EXPERIMENTAL_FEATURES` environment variable.
  • inputThe attacker must be able to craft and deliver a forged `FeatureAuthorization` ActivityStreams object.
  • networkThe attack is performed over the network against a Mastodon instance that processes remote Collection items.

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

References

2

News mentions

0

No linked articles in our index yet.