CVE-2026-105679 Overview
CVE-2026-105679 affects Ghost, a Node.js content management system (CMS). In versions from 6.22.1 up to but not including 6.64.0, Ghost's protection that forced uploaded files to be served with an inert content type was not applied when sites used the default local storage adapter. Any authenticated staff user could upload a file whose extension caused the server to return an executable content type such as text/html or application/javascript. An attacker could host scripts on the site's own domain and compromise other staff users' admin sessions. The flaw is classified as [CWE-79] Cross-Site Scripting (XSS). Ghost resolved the issue in version 6.64.0.
Critical Impact
An authenticated staff user can upload script content served from the Ghost site's origin, enabling stored XSS that targets admin sessions and can lead to full administrative compromise.
Affected Products
- Ghost (Node.js CMS) versions 6.22.1 through 6.63.x
- Ghost deployments using the default local storage adapter
- Self-hosted Ghost instances serving uploads from /content/files/
Discovery Timeline
- 2026-10-05 - CVE-2026-105679 published to NVD
- 2026-10-06 - Last updated in NVD database
- Ghost v6.64.0 - Vendor releases security patch (commit 58669d5c8b898f8b69c1287c2779b29ecc7eb918)
Technical Details for CVE-2026-105679
Vulnerability Analysis
Ghost's upload pipeline is designed to prevent browsers from executing uploaded files. The platform forces responses for user-uploaded content to use an inert MIME type such as text/plain combined with the X-Content-Type-Options: nosniff header. This hardening blocks stored XSS when uploads are served from the same origin as the admin panel.
The local storage adapter did not enforce this restriction. Files written to /content/files/ were served with a content type derived from the file extension. A staff user with upload rights could place an .html, .svg, or .js file in that path and have the browser execute it when another admin visited the URL. Because the script runs on the Ghost origin, it inherits access to the admin session cookie and the Admin API.
The advisory classifies the issue as [CWE-79] Cross-Site Scripting. Exploitation requires valid staff credentials and user interaction, but the impact extends to confidentiality and integrity of the full site.
Root Cause
The LocalFileStorage adapter bypassed the shared middleware that normalizes response headers for uploaded assets. Instead, the Express static handler used Node's default MIME lookup against the file extension. The result was that /content/files/evil.html returned Content-Type: text/html without the nosniff directive, allowing script execution in-browser.
Attack Vector
An attacker needs a Ghost staff account with upload permissions. The actor uploads a file containing JavaScript or HTML through the standard files endpoint, obtains the public URL under /content/files/, and delivers that URL to another administrator through a post, email, or social-engineered link. When the admin loads the URL, the payload executes in the Ghost origin and can read session state, invoke Admin API endpoints, or persist a backdoor user.
// Patch excerpt — e2e/Dockerfile.e2e (sanitized documentation of the fix intent)
// Source: https://github.com/TryGhost/Ghost/commit/58669d5c8b898f8b69c1287c2779b29ecc7eb918
- # Public app UMD bundles — Ghost serves these from /content/files/
- COPY apps/portal/umd /home/ghost/content/files/portal
- COPY apps/comments-ui/umd /home/ghost/content/files/comments-ui
- COPY apps/sodo-search/umd /home/ghost/content/files/sodo-search
- COPY apps/signup-form/umd /home/ghost/content/files/signup-form
- COPY apps/announcement-bar/umd /home/ghost/content/files/announcement-bar
+ # Public app UMD bundles — Ghost serves core/built/admin/assets at /ghost/assets/
+ COPY apps/portal/umd /home/ghost/core/built/admin/assets/portal
+ COPY apps/comments-ui/umd /home/ghost/core/built/admin/assets/comments-ui
+
+ # Don't serve them from /content/files/ — uploaded files there are deliberately
+ # served as inert types (text/plain + nosniff), so browsers won't execute the scripts.
The patch moves trusted bundles out of /content/files/ and documents that the uploads path must remain inert. See the GitHub commit details for the full change set.
Detection Methods for CVE-2026-105679
Indicators of Compromise
- Files with executable extensions such as .html, .htm, .svg, .js, or .xhtml present under /content/files/ on local-storage deployments.
- HTTP responses from /content/files/* returning Content-Type: text/html or application/javascript instead of text/plain.
- Unexpected staff user creations, invitations, or role changes recorded in the Ghost activity log following a file upload.
- Admin sessions originating from new IP addresses or user agents shortly after a staff member opens a /content/files/ URL.
Detection Strategies
- Audit the local uploads directory for files whose extensions could trigger browser rendering and inspect their content for <script> tags or inline event handlers.
- Issue HEAD requests against a sample of files under /content/files/ and alert on responses missing X-Content-Type-Options: nosniff or returning active MIME types.
- Correlate Ghost Admin API audit events (user creation, API key generation, integration changes) with recent file upload activity by the same session.
Monitoring Recommendations
- Forward Ghost application logs and reverse-proxy access logs to a central analytics platform and build a rule that flags executable content types served from the uploads path.
- Monitor outbound requests from browsers accessing the Ghost admin console for anomalous POSTs to the Admin API that follow a /content/files/ fetch.
- Track the Ghost version string reported by /ghost/api/admin/site/ and alert when any instance remains below 6.64.0.
How to Mitigate CVE-2026-105679
Immediate Actions Required
- Upgrade all Ghost instances to version 6.64.0 or later as published in the GitHub release v6.64.0.
- Review staff accounts, revoke dormant users with upload rights, and rotate any Admin API keys that may have been exposed during the vulnerable window.
- Invalidate active admin sessions after upgrade to force re-authentication for every staff member.
- Scan /content/files/ for files uploaded since version 6.22.1 was deployed and quarantine any with script-capable content types.
Patch Information
The fix is included in Ghost 6.64.0, delivered through commit 58669d5c8b898f8b69c1287c2779b29ecc7eb918 as part of pull request #30762. The patch extends the inert content-type handling to the local storage adapter so that files served from /content/files/ consistently return text/plain with X-Content-Type-Options: nosniff. Full technical details are documented in GHSA-gfjp-2p8f-94qv.
Workarounds
- Place a reverse proxy such as NGINX or Caddy in front of Ghost and override the Content-Type for /content/files/* to text/plain while adding X-Content-Type-Options: nosniff.
- Switch from the default local storage adapter to an external object store (for example, S3-compatible storage) served from a separate origin without admin cookies.
- Restrict staff invitations and reduce the number of accounts with upload privileges until the upgrade is applied.
# NGINX reverse-proxy mitigation for Ghost /content/files/
location ^~ /content/files/ {
proxy_pass http://ghost_upstream;
proxy_hide_header Content-Type;
add_header Content-Type "text/plain" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Content-Security-Policy "default-src 'none'; sandbox;" always;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.