Executive brief
Tiptap's mergeAttributes() function, a core utility for combining DOM element properties, fails to safely handle the `__proto__` key from untrusted JSON input. An attacker who controls document attributes, plugin configurations, or CMS data can inject a malicious prototype that becomes invisible to normal property checks but gets applied as executable DOM attributes (like event handlers) when the editor renders content. This enables arbitrary JavaScript execution within the application's security context.
Technical details
The vulnerability is a prototype pollution flaw in @tiptap/core's mergeAttributes() function. When processing object keys via Object.entries(), the function uses simple bracket notation (mergedAttributes[key] = value) without filtering the `__proto__` key. In JavaScript, assigning to __proto__ invokes the legacy prototype setter, replacing the object's prototype with attacker-controlled content. This creates "hidden" inherited properties—invisible to Object.keys() and own-property checks but enumerable via for...in loops. When ProseMirror's DOMSerializer processes the result, it enumerates inherited keys and applies them via setAttribute(), allowing injection of event handlers like onerror that execute in the browser. Exploitation requires an untrusted object boundary into mergeAttributes() or a dynamic/custom schema that preserves attributes. The fix (version 3.30.4) filters out __proto__ or uses Object.defineProperty to prevent prototype setter invocation. No public exploits have been disclosed.
Affected products
- ueberdosis @tiptap/core 2.0.0-alpha.0 through 3.29.2
Timeline
- 2026-08-26: disclosed: GitHub Security Advisory published (private report)
- 2026-09-02: patched: Fix released in @tiptap/core 3.30.4
- 2026-09-02: advisory: GHSA-cp6q-959q-f8rh published to GitHub Advisory Database