GHSA-44JG-MV3H-WJ6G

Spreadsheet of Doom: XSS in Craft CMS Freeform via Font Names

Alon Barad
Alon Barad
Software Engineer

Jan 16, 2026·5 min read

Executive Summary (TL;DR)

The Solspace Freeform plugin relies on `PhpSpreadsheet` to handle Excel files. A flaw in how that library converts spreadsheets to HTML allows attackers to inject malicious JavaScript into the *font name* of a cell. When an admin previews a submitted form containing a malicious Excel file, the script executes, potentially leading to full account takeover.

A high-severity Cross-Site Scripting (XSS) vulnerability exists in the Solspace Freeform plugin for Craft CMS, inherited from the upstream PhpSpreadsheet library. By manipulating metadata within an Excel file—specifically the font name—an attacker can execute arbitrary JavaScript in the browser of an administrator viewing the file.

The Hook: When Spreadsheets Go Rogue

We often think of Excel files as dangerous because of Macros (VBA). We've spent decades training users not to click 'Enable Content'. But what if the file didn't need macros to hurt you? What if the file structure itself—the very metadata defining how pretty the cells look—was the weapon?

Enter solspace/craft-freeform, a premier form building plugin for Craft CMS. It's the go-to tool for heavy-duty data collection, often handling file uploads and exports. It relies on the ubiquitous PhpSpreadsheet library to parse and display spreadsheet data.

Here's the kicker: PhpSpreadsheet has a feature to convert spreadsheet views into HTML tables for easy web viewing. This feature had a blind spot the size of a truck: it trusted that font names were just names, not disguised HTML kill-switches.

The Flaw: Trusting the Font

The vulnerability (inherited from CVE-2024-45046) lies in the \PhpOffice\PhpSpreadsheet\Writer\Html class. When this class converts a workbook to HTML, it iterates through the styling properties of the cells to generate corresponding CSS or inline styles.

Normally, if you set a cell's font to 'Arial', the code generates something harmless like font-family: Arial;. But the library developers made a classic assumption: they assumed a font name string would only contain... well, font names.

They didn't sanitize it. They took the string directly from the XML structure of the .xlsx file and concatenated it into the HTML output. This is a textbook Injection flaw, but in a place very few people think to look. Who expects a font named "><script>alert(1)</script>?

The Code: The Silent Failure

Let's look at how innocent the usage looks in PHP. This snippet is all it takes to trigger the vulnerability. If Freeform (or any application) takes a user-uploaded file and tries to render it for a preview using the HTML writer, it's game over.

// The setup looks standard
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader("Xlsx");
$spreadsheet = $reader->load("malicious_upload.xlsx");
 
// The writer is where the magic (and the horror) happens
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Html($spreadsheet);
 
// This function blindly dumps the font name into the markup
echo $writer->generateHTMLAll();

Under the hood, the vulnerable versions of the library were effectively doing this (pseudo-code):

// Vulnerable Logic
$css .= 'font-family: ' . $style->getFont()->getName();

Because there was no htmlspecialchars() or equivalent sanitization wrapping that getName() call, the browser interprets the closing quote and bracket from the attacker's payload as the end of the style tag, and executes whatever comes next.

The Exploit: Crafting the Payload

Exploiting this doesn't require complex binary hacking. An .xlsx file is just a zipped archive of XML files. Here is how a researcher—or an attacker—would weaponize this:

  1. Create a blank Excel file. Open it in a zip utility.
  2. Locate the styles. Find the xl/styles.xml file inside the archive. This defines the look and feel of the workbook.
  3. Inject the Payload. Find the <fonts> section. Replace a font name attribute (usually val="Calibri") with your payload: val="\"><img src=x onerror=alert(document.cookie)>"
  4. Repackage. Zip it back up and rename it to .xlsx.
  5. Delivery. Submit this file to a Craft CMS site using a Freeform form that accepts uploads.

When the unsuspecting administrator logs into the Control Panel and clicks to preview the submission or view the file details (if rendered by the plugin), the browser attempts to render the font family. It hits the quote, breaks out of the CSS context, and fires the onerror event of the image tag.

The Impact: Admin Takeover

This is a Stored XSS, and it's a nasty one because of where it fires. It triggers inside the Craft CMS Control Panel—the holy of holies for a site.

If an attacker's JavaScript executes in the context of a logged-in Admin:

  • Session Hijacking: They can steal the CraftSessionId cookie.
  • RCE escalation: In many CMS setups, admins can edit templates. If an admin can edit Twig templates, they can execute PHP code. Therefore, XSS on an Admin often equals Remote Code Execution (RCE).
  • Shadow Accounts: They can silently create a new admin user via API calls in the background while the victim is just staring at a broken spreadsheet preview.

The Fix: Sanitation Department

Solspace released Freeform 4.1.23 to address this. The fix wasn't a complex code change in Freeform itself, but rather a dependency bump. They updated their composer.json to require a patched version of phpoffice/phpspreadsheet (specifically versions ^2.0 or ^3.0 which contain the fix).

The fix in the upstream library involves strictly escaping the font name before outputting it to HTML, ensuring that "><script> becomes &quot;&gt;&lt;script&gt;—boring text instead of executable code.

To Fix: run composer update in your Craft CMS project root to pull in the latest Freeform version and its dependencies.

Technical Appendix

CVSS Score
7.1/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

Craft CMS websites using Solspace Freeform pluginPHP applications using older versions of PhpSpreadsheet

Affected Versions Detail

Product
Affected Versions
Fixed Version
solspace/craft-freeform
Solspace
< 4.1.234.1.23
AttributeDetail
Vulnerability TypeCross-Site Scripting (XSS)
Root CauseImproper Output Neutralization for Logs/Messages (CWE-116)
CVSS Score7.1 (High)
Attack VectorNetwork (User Interaction Required)
Affected ComponentPhpSpreadsheet\Writer\Html
Exploit StatusPoC Available
CWE-79
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

The software does not properly neutralize output for downstream components, allowing special characters to be interpreted as control sequences or code.

Vulnerability Timeline

Vulnerability Published
2024-10-06
Freeform 4.1.23 Released with Fix
2024-10-06

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.