Mastodon: Persistent federated DoS via unhandled NoMethodError in MATH_TRANSFORMER

Any remote ActivityPub server can use a single signed message to persistently take down the federated public timeline of every reachable Mastodon instance with HTTP 500, without holding an account on the target.

Advisory ID: TP-2026-006
Product: Mastodon (federated social network / microblogging server)
Vulnerability type: Denial of service via unhandled exception (CWE-755)
CVE: CVE-2026-50129
CVSS 3.1: 7.5 (High) · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Vendor advisory: GHSA-qrgq-9fx2-vf2r
Fixed in: 4.5.11, 4.4.18, 4.3.24
Reported: 22 May 2026

Summary

Mastodon is a widely used server for a federated social network (ActivityPub). Inbound HTML content of federated statuses is run through a sanitizer whose MATH_TRANSFORMER lambda raises a NoMethodError on an <annotation> element that has no encoding attribute. The only rescue block in the formatting path catches ArgumentError alone, so the exception propagates up to the Rails error handler and yields an HTTP 500. Because Mastodon stores the raw HTML of federated content unchecked, every later render path of that status crashes again. turingpoint verified the end-to-end flow as a stored, anonymously triggerable, federation-amplified DoS against a running instance.

Root cause

Mastodon sanitizes inbound federated status HTML via Sanitize.fragment(..., MASTODON_STRICT), whose MATH_TRANSFORMER lambda converts <math><semantics><annotation> nodes into text (lib/sanitize_ext/sanitize_config.rb:75-104). When the <annotation> element lacks the encoding attribute, node.attributes['encoding'] returns nil, and the directly chained .value call raises NoMethodError: undefined method 'value' for nil (lib/sanitize_ext/sanitize_config.rb:87). The only rescue block in the formatting path catches ArgumentError alone (app/lib/html_aware_formatter.rb:23), so the NoMethodError propagates uncaught up to the Rails error handler and produces an HTTP 500. Only remote, federated statuses trigger the bug, because local posts run through linkify/TextFormatter with no math transform, while remote content is routed through reformat into the MATH_TRANSFORMER and its raw HTML is persisted unchecked (app/lib/activitypub/parser/status_parser.rb:48). Because the admin moderation view calls the same formatting path (app/views/admin/shared/_status_content.html.haml:13), every rendering of the poisoned status crashes again and the admin UI can no longer display it.

Proof of Concept

A single signed ActivityPub message from any remote instance is enough. The <annotation> node carries no encoding attribute:

POST /inbox   (HTTP signature of a remote ActivityPub actor)

{
  "type": "Create",
  "object": {
    "type": "Note",
    "content": "<math><semantics><annotation>x</annotation></semantics></math>"
  }
}

The instance accepts the activity (HTTP 202) and stores the raw HTML. On the first render the .value call inside MATH_TRANSFORMER raises the NoMethodError; because the status is persisted, every subsequent request to the federated public timeline and every further render path (RSS, search index, outbound federation) then returns HTTP 500 again.

Impact

  • A single signed Create{Note} message from any remote instance poisons the federated public timeline of every reachable Mastodon instance, anonymously and without an account on the target.
  • Every render path of the status (public timeline, RSS feed, search index, outbound federation to followers) ends in HTTP 500.
  • The admin moderation interface calls the same formatting path and cannot display the status; cleanup requires direct deletion via the database or the Rails console.
  • Persistent availability impact on timeline and moderation until the status is removed manually.

References

Is Something Like This in Your Software?

Our team found this vulnerability in the course of its work. Have your applications tested by the same specialists, with a penetration test from turingpoint.