Intelligence
criticalVulnerabilityActive

Cache-Poisoning XSS via x-ghost-preview Header in Ghost CMS

Ghost CMS fails to properly validate the x-ghost-preview header, allowing unauthenticated attackers to inject malicious content into cached responses. When frontend and admin share a domain, this enables account takeover of staff users.

S
Sebastion

CVE References

Affected

Ghost/Ghost v4.0 through v6.36.0

Vulnerability Description

This vulnerability is a cache-poisoning cross-site scripting (XSS) flaw in Ghost CMS affecting versions 4.0 through 6.36.0. The root cause is insufficient validation of the x-ghost-preview header in the request processing pipeline. When Ghost operates behind a shared caching layer (Fastly, Cloudflare, nginx, etc.), an attacker can inject arbitrary content via this header. The server renders the malicious payload into the response, and if cache key derivation fails to include this header's value, the poisoned response becomes cached and served to legitimate users. The impact escalates significantly when Ghost's frontend and admin panel share the same domain—cached XSS payloads can harvest staff authentication tokens or session cookies, leading to account takeover.

Proof-of-Concept Significance

A working PoC demonstrates that: (1) the header is processed by the rendering engine without sanitization, (2) responses can be cached despite request-specific header values, and (3) cache keys do not properly differentiate between authenticated preview requests and public responses. The reliability of exploitation depends on cache configuration—shared caching layers with weak cache-key strategies are high-risk. Preconditions include: (a) Ghost deployed behind a caching proxy, (b) frontend and admin on the same domain (optional but critical for account takeover), and (c) unauthenticated network access to craft malicious requests.

Detection Guidance

Log Indicators:

  • HTTP requests with x-ghost-preview header containing suspicious payloads (script tags, event handlers, protocol schemes like javascript:)
  • Anomalous cache HIT responses for requests with non-standard x-ghost-preview values
  • 200 OK responses to requests bearing x-ghost-preview headers that should trigger 403/404 for unauthenticated users

Monitoring:

  • Track cache layer headers: X-Cache, X-Cache-Status, Age for responses containing x-ghost-preview
  • Alert on x-ghost-preview header in requests from non-preview endpoints (e.g., / or /admin)
  • Monitor for encoded or obfuscated payloads in header values (Base64, Unicode escapes)

Mitigation Steps

Immediate Actions:

  1. Upgrade to v6.37.0 or later (patched version that validates/sanitizes the header)
  2. Cache layer bypass: Configure your caching proxy to skip cache for any request containing x-ghost-preview header
  3. Domain separation: If possible, host admin on a separate domain to prevent XSS→account takeover chains
  4. Cache-key augmentation: Ensure cache keys include the x-ghost-preview header value to prevent poisoning
  5. Reset credentials: For Ghost v6.41.0+, use Settings / Danger Zone / "Reset all authentication" if breach is suspected

Long-term Hardening:

  • Implement Content-Security-Policy (CSP) headers to limit inline script execution
  • Use HTTP-only and Secure flags on session cookies
  • Enable SameSite cookie attribute (Strict or Lax)

Risk Assessment

Likelihood of Wild Exploitation: HIGH. Many Ghost instances run behind shared caching layers without proper cache-key configuration. The attack requires no authentication and minimal sophistication. Threat Actor Interest: CRITICAL. Staff account compromise enables: admin panel access, data exfiltration, malware distribution via themes, and lateral movement. Public PoC availability and simplicity of header manipulation make this attractive for opportunistic attacks. Organizations running Ghost 4.0–6.36.0 with shared caching should treat this as a priority patch event. Organizations with admin/frontend domain separation have reduced but non-zero risk (persistent XSS on public frontend).