Skip to main content
Vulnerability Database/CVE-2026-105649

CVE-2026-105649: Ghost CMS XSS Vulnerability

CVE-2026-105649 is a cross-site scripting flaw in Ghost CMS that allows staff users to upload malicious SVG files, potentially compromising admin sessions. This article covers the technical details, affected versions, and mitigation steps.

Published:

CVE-2026-105649 Overview

CVE-2026-105649 is a stored cross-site scripting (XSS) vulnerability in Ghost, a Node.js content management system. The flaw affects versions 4.22.0 through 6.64.x and was fixed in version 6.65.0. Ghost stored SVG media thumbnails and SVG images uploaded with a non-SVG file extension without sanitization. Any staff user, including users with the Contributor role, could host attacker-controlled scripts on the site's own domain. Those scripts could execute in the browser of other staff users and compromise their administrative sessions. The weakness is classified under CWE-79: Improper Neutralization of Input During Web Page Generation.

Critical Impact

A low-privileged Contributor can upload a malicious SVG and hijack an authenticated administrator session, leading to full site takeover.

Affected Products

  • Ghost versions 4.22.0 through 6.64.x
  • Ghost self-hosted Node.js deployments serving user-uploaded media
  • Ghost installations using storage adapters that honor the uploaded content type (for example, Amazon S3)

Discovery Timeline

  • 2026-10-05 - CVE-2026-105649 published to the National Vulnerability Database
  • 2026-10-06 - Last updated in the NVD database
  • Ghost v6.65.0 - Vendor releases the patched version containing the SVG validation fix

Technical Details for CVE-2026-105649

Vulnerability Analysis

The vulnerability is a stored XSS condition in Ghost's media upload pipeline. SVG files are XML documents and can contain <script> elements that execute when the browser renders the file as image/svg+xml. Ghost sanitized SVGs identified by their .svg extension but did not apply the same sanitization to SVG thumbnails or to SVG payloads uploaded with a non-SVG extension. Storage adapters such as Amazon S3 persist and serve files using the uploaded content type. An attacker could upload an SVG with a benign-looking extension while declaring image/svg+xml as the content type, causing the storage backend to serve the file as a script-executing SVG. Because the file is served from the Ghost site's own origin, the resulting script runs with full access to the session cookies and admin API of any staff user who loads it.

Root Cause

The upload middleware in ghost/core/core/server/web/api/middleware/upload.js evaluated the file extension and the MIME type independently. SVG detection relied on extension matching alone for sanitization, while the storage layer honored the declared content type. This inconsistency allowed SVG content to bypass sanitization whenever the extension and content type disagreed. Thumbnail generation also failed to invoke SVG sanitization before persisting the output.

Attack Vector

Exploitation requires an authenticated staff account at any privilege tier, including Contributor. The attacker uploads a crafted SVG through the media or thumbnail upload endpoint, using a non-SVG extension paired with the image/svg+xml content type. The storage adapter writes the file and later serves it as an SVG under the Ghost origin. When an administrator views the uploaded asset, the embedded script executes in the admin's browser context and can issue authenticated requests against the Ghost Admin API.

javascript
// Patch: ghost/core/core/server/web/api/middleware/upload.js
// Source: https://github.com/TryGhost/Ghost/commit/80686226d23df56749f6b7ebb484850a8eba8072

  return await fs.writeFile(filepath, content);
};

/**
 *
 * @param {{ext: string, type: string}} file
 * @returns {boolean}
 *
 * Extension and content type are allowlisted separately, so a file counts as an SVG if either
 * one says so. Storage adapters that use the content type (e.g. S3) would otherwise serve an
 * unsanitized SVG uploaded with a non-SVG extension as image/svg+xml.
 */
const isSvgFile = (file) => {
  return file.ext === '.svg' || file.ext === '.svgz' || file.type === 'image/svg+xml';
};

The fix introduces isSvgFile(), which treats a file as an SVG when either the extension or the content type indicates SVG. Sanitization now runs across both detection paths.

Detection Methods for CVE-2026-105649

Indicators of Compromise

  • Files served from the Ghost /content/images/ path with a non-SVG extension but a Content-Type: image/svg+xml response header
  • SVG assets containing <script>, onload=, or javascript: payloads in the content store or S3 bucket
  • Media uploads originating from Contributor or Author accounts followed by administrative session anomalies

Detection Strategies

  • Scan the Ghost content directory and object storage buckets for files whose stored content type is image/svg+xml but whose extension is not .svg or .svgz
  • Parse recent SVG uploads for inline scripts, event handlers, and external script references
  • Correlate upload events from low-privileged staff accounts with subsequent admin API calls from unusual IP addresses or user agents

Monitoring Recommendations

  • Enable audit logging for all /ghost/api/admin/images/upload/ and thumbnail upload endpoints
  • Alert on administrator session activity that follows media access from newly uploaded assets
  • Monitor outbound requests from browsers rendering Ghost admin pages for connections to unexpected domains

How to Mitigate CVE-2026-105649

Immediate Actions Required

  • Upgrade Ghost to version 6.65.0 or later on all self-hosted instances
  • Audit existing uploads for SVG payloads stored under non-SVG extensions and remove or re-sanitize any affected files
  • Review staff account activity for unauthorized Contributor or Author registrations and rotate admin credentials and session secrets if compromise is suspected

Patch Information

The fix is included in Ghost v6.65.0. Review the GitHub Security Advisory GHSA-8575-cr6v-7jh4, the upstream commit 80686226, GitHub Issue #30919, and the Ghost v6.65.0 release notes.

Workarounds

  • Block uploads with the image/svg+xml content type at the reverse proxy or Web Application Firewall until the patched version is deployed
  • Restrict staff account creation and temporarily downgrade untrusted Contributor accounts
  • Serve user-uploaded media from an isolated origin so that script execution does not inherit the Ghost admin session context
bash
# Example nginx rule to reject SVG content-type uploads at the edge
location /ghost/api/admin/images/upload/ {
    if ($http_content_type ~* "image/svg\+xml") {
        return 415;
    }
    proxy_pass http://ghost_backend;
}

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.