CVE-2026-55103 Overview
CVE-2026-55103 affects the Discourse ActivityPub plugin, which adds federation support to Discourse forums via the ActivityPub protocol. The vulnerability stems from insufficient verification that the actor authenticated by a signed inbound request matches the Activity actor and owns the referenced federated post. A remote, unauthenticated attacker can abuse the missing identity and ownership checks to edit, delete, or reply to federated posts belonging to other users. The issue is categorized under [CWE-345: Insufficient Verification of Data Authenticity]. The maintainers remediated the flaw in commit 1c8518b0f2abdf31cbea3e0b242f74d8994a9ba5.
Critical Impact
Remote attackers can impersonate federated actors to tamper with posts across any Discourse instance running the ActivityPub plugin prior to the fix commit.
Affected Products
- Discourse ActivityPub plugin (discourse-activity-pub)
- All versions prior to commit 1c8518b0f2abdf31cbea3e0b242f74d8994a9ba5
- Discourse forums with federation enabled via the ActivityPub plugin
Discovery Timeline
- 2026-10-15 - CVE-2026-55103 published to NVD
- 2026-10-16 - Last updated in NVD database
Technical Details for CVE-2026-55103
Vulnerability Analysis
The Discourse ActivityPub plugin exposes HTTP inbox endpoints that receive federated Activities (Create, Update, Delete, and similar) from remote servers. ActivityPub relies on HTTP Signatures to authenticate the sending actor. Before the fix, the inbox controllers validated the signature but did not cross-check the signed actor against the actor field inside the Activity payload or against the owner of the target post.
This gap allowed any federated actor to submit Activities referencing posts owned by other actors. The server processed those Activities as if they were authorized, enabling tampering with federated content. The weakness aligns with CWE-345 because the application trusted inbound data without verifying its authenticity relative to the authenticated principal.
Root Cause
The inbox processing jobs received only the raw JSON Activity and the delivery target. They did not receive the identity of the signed-request actor, so downstream authorization logic could not compare it against the embedded actor or the post owner. The missing linkage between transport-layer authentication and application-layer authorization is the root cause.
Attack Vector
An attacker controlling any federated ActivityPub actor sends a signed HTTP POST to a vulnerable Discourse instance's inbox or shared inbox. The signed request uses the attacker's own key, while the embedded Activity references a post owned by a different actor. The server accepts and processes the Activity, allowing edits, deletions, or replies without authorization.
# Patch excerpt from app/controllers/discourse_activity_pub/a_p/inboxes_controller.rb
def process_json
- Jobs.enqueue(Jobs::DiscourseActivityPub::Process, json: @json, delivered_to: @actor.ap_id)
+ Jobs.enqueue(
+ Jobs::DiscourseActivityPub::Process,
+ json: @json,
+ delivered_to: @actor.ap_id,
+ signed_actor_ap_id: signed_request_actor&.ap_id,
+ )
end
# Patch excerpt from app/controllers/discourse_activity_pub/a_p/shared_inboxes_controller.rb
def process_json
- Jobs.enqueue(Jobs::DiscourseActivityPub::Process, json: @json)
+ Jobs.enqueue(
+ Jobs::DiscourseActivityPub::Process,
+ json: @json,
+ signed_actor_ap_id: signed_request_actor&.ap_id,
+ )
end
# Source: https://github.com/discourse/discourse-activity-pub/commit/1c8518b0f2abdf31cbea3e0b242f74d8994a9ba5
The fix forwards signed_request_actor&.ap_id into the background processor so later stages can verify the signer owns the referenced Activity and post.
Detect Identity Attacks the Moment Authentication Fails
Singularity™ Identity surfaces credential misuse, lateral movement, and privilege escalation in real time, so you can contain the breach before it spreads.
Stop Identity AttacksDetection Methods for CVE-2026-55103
Indicators of Compromise
- Inbox requests where the HTTP Signature keyId resolves to an actor different from the actor field in the Activity JSON.
- Unexpected Update, Delete, or Reply Activities targeting posts whose attributedTo value does not match the signing actor.
- Audit log entries showing federated edits or deletions without a corresponding local user action.
Detection Strategies
- Parse Discourse application logs for /ap/inbox and /ap/shared-inbox POSTs and compare the signing actor against the embedded Activity actor.
- Alert on federated Activities that modify or remove posts attributed to a different domain than the signing actor's domain.
- Review Sidekiq job history for Jobs::DiscourseActivityPub::Process entries that lack a matching signed_actor_ap_id prior to the patch.
Monitoring Recommendations
- Enable verbose logging on ActivityPub inbox controllers to retain signature metadata for forensic review.
- Monitor outbound federation reports and user complaints about unauthorized post edits or deletions.
- Track volume anomalies in federated Update and Delete Activities per remote domain.
How to Mitigate CVE-2026-55103
Immediate Actions Required
- Update the discourse-activity-pub plugin to a build that includes commit 1c8518b0f2abdf31cbea3e0b242f74d8994a9ba5 or later.
- Rebuild the Discourse container after updating plugins and restart the application.
- Audit federated posts for unauthorized edits, deletions, or replies that occurred before patching.
Patch Information
The fix is contained in commit 1c8518b0f2abdf31cbea3e0b242f74d8994a9ba5 of the discourse/discourse-activity-pub repository. Patched controllers propagate the HTTP-signature actor into the processing job, enabling authoritative ownership checks against each Activity's actor and target post. Refer to the GitHub Security Advisory GHSA-jw39-rch6-mhwf and the upstream commit for implementation details.
Workarounds
- Temporarily disable the ActivityPub plugin in Discourse admin settings if immediate patching is not possible.
- Restrict access to /ap/inbox and /ap/shared-inbox endpoints at the reverse proxy to a vetted allowlist of federated peers.
- Pause federation with untrusted instances until the patched plugin build is deployed.
# Update the plugin and rebuild the Discourse app container
cd /var/discourse
git -C containers/plugins/discourse-activity-pub pull
./launcher rebuild app
# Verify the patched commit is present
docker exec app bash -c "cd /var/www/discourse/plugins/discourse-activity-pub && git log --oneline | grep 1c8518b0"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

