CVE-2026-47110 Overview
CVE-2026-47110 is a denial of service vulnerability in Tiptap for PHP versions prior to 2.1.1. The flaw resides in the Link::isAllowedUri() function, which passes the attrs.href field directly to preg_match() without validating that the value is a string. Authenticated attackers can submit Tiptap JSON containing an array in the attrs.href field, triggering an unhandled TypeError. Because the malformed JSON can be persisted in the database, every subsequent attempt to render the affected record will crash the server-side HTML rendering pipeline. The condition persists until an administrator manually repairs the database entry.
Critical Impact
Authenticated attackers can persistently break the HTML rendering pipeline for any record containing a malformed href array, denying service to all viewers until manual database remediation occurs.
Affected Products
- Tiptap for PHP versions before 2.1.1
- Applications integrating ueberdosis/tiptap-php for content rendering
- PHP backends performing server-side rendering of Tiptap JSON documents
Discovery Timeline
- 2026-06-24 - CVE-2026-47110 published to NVD
- 2026-06-24 - Last updated in NVD database
Technical Details for CVE-2026-47110
Vulnerability Analysis
The vulnerability is classified under [CWE-241] (Improper Handling of Unexpected Data Type). Tiptap for PHP converts ProseMirror/Tiptap JSON documents into HTML by walking the node tree and applying registered marks. The Link mark validates URIs through Link::isAllowedUri(), which is invoked during HTML generation.
The function assumes attrs.href is always a string and forwards the value to preg_replace() and preg_match(). PHP's PCRE functions require a string $subject argument. When an array is supplied, PHP 8 raises an uncaught TypeError, terminating the request with a fatal error.
Because Tiptap content is typically stored in a database after client submission, an attacker can poison a single record. Every subsequent render request for that record triggers the same TypeError, producing a persistent denial of service against all users who view the affected content.
Root Cause
The root cause is missing type validation on user-controlled input before passing it to PCRE functions. The attrs.href attribute is treated as trusted string data, but the JSON specification permits any value type. No is_string() guard existed prior to version 2.1.1, allowing arrays, objects, or other non-string values to reach preg_match().
Attack Vector
An authenticated attacker submits a Tiptap JSON document where a link mark contains a non-string href, for example "attrs": { "href": ["https://example.com"] }. The application stores the document. Any subsequent rendering operation invokes Link::isAllowedUri() and crashes with a TypeError, producing HTTP 500 responses for every viewer of that record.
// Security patch in src/Marks/Link.php
// Source: https://github.com/ueberdosis/tiptap-php/commit/74bfb7be1c8c6102b240f3879b7f984a6ab87b97
return true;
}
+ if (! is_string($uri)) {
+ return false;
+ }
+
$sanitised = preg_replace(self::ATTR_WHITESPACE, '', $uri);
$pattern = '/^(?:(?:' . implode('|', array_map('preg_quote', $this->options['allowedProtocols']))
The patch adds an is_string() guard that returns false for any non-string $uri, preventing the TypeError from reaching preg_replace() and preg_match().
Detection Methods for CVE-2026-47110
Indicators of Compromise
- PHP error logs containing TypeError exceptions originating in Link::isAllowedUri() or preg_match() with array argument messages
- HTTP 500 responses correlated with rendering requests for specific content records
- Stored Tiptap JSON documents where attrs.href is an array, object, or non-string scalar
- Repeated render failures isolated to individual database entries rather than systemwide errors
Detection Strategies
- Scan persisted Tiptap JSON columns for href attributes whose value is not a JSON string, using database queries or JSON path expressions
- Add application-layer logging that captures the document ID and submitting user when isAllowedUri() returns false or throws
- Alert on spikes of HTTP 500 responses tied to content rendering endpoints in the web tier
Monitoring Recommendations
- Forward PHP error_log output to a centralized logging system and create alerts on TypeError in tiptap-php namespaces
- Track per-record render failure rates to identify poisoned database entries quickly
- Monitor authenticated content submission endpoints for malformed JSON structures and rate-limit abusive accounts
How to Mitigate CVE-2026-47110
Immediate Actions Required
- Upgrade ueberdosis/tiptap-php to version 2.1.1 or later via Composer
- Audit existing stored Tiptap documents for non-string href values and repair or remove affected records
- Review authenticated user submission paths to identify accounts that may have planted malformed documents
- Restrict content submission privileges to trusted roles until the upgrade is deployed
Patch Information
The fix is available in Tiptap for PHP release 2.1.1 and was merged via pull request #94. The change is implemented in commit 74bfb7be, which adds an is_string() check in src/Marks/Link.php before invoking PCRE functions. Additional context is available in the VulnCheck advisory.
Workarounds
- Validate Tiptap JSON server-side before storage, rejecting documents where any attrs.href is not a string
- Wrap calls into the Tiptap renderer with a try/catch for TypeError to degrade gracefully while remediating
- Apply a custom subclass or extension override of Link::isAllowedUri() that enforces is_string() if upgrading is not immediately feasible
# Configuration example: upgrade and verify version
composer require ueberdosis/tiptap-php:^2.1.1
composer show ueberdosis/tiptap-php | grep versions
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

