Jul 7, 2026·7 min read·17 visits
Unauthenticated DOM-based XSS in Craft CMS Support Widget via untrusted GitHub API issue titles, patched in 4.17.16 and 5.9.23.
A DOM-based cross-site scripting (XSS) vulnerability exists in Craft CMS versions 4.0.0-RC1 through 4.17.15 and 5.0.0-RC1 through 5.9.22. The flaw resides within the CraftSupport widget's feedback search component, which fails to neutralize GitHub issue titles before rendering them into the administrator's control panel. An unauthenticated attacker can exploit this vulnerability by submitting a crafted issue to the public Craft CMS repository on GitHub.
Craft CMS incorporates an administrative control panel that provides content managers and system administrators with tools to manage web assets, users, and system configurations. To facilitate customer support and troubleshooting, the platform includes a default dashboard component called the CraftSupport widget. This widget allows administrators to search for public issues, submit feedback, and review error logs directly from their active control panel interface.
The search functionality exposes an external attack surface by interacting directly with the public GitHub API. When an administrator initiates a search within the 'Give feedback' screen, the widget queries the public repository 'craftcms/cms' on GitHub. Because the widget processes external, third-party data dynamically on the client side, it introduces a trust boundary issue between the local administrative session and remote public content.
The core vulnerability is classified as a DOM-based Cross-Site Scripting (XSS) flaw under CWE-79. Because the application does not properly sanitize the retrieved issue titles before appending them to the Document Object Model (DOM), arbitrary markup within those titles executes immediately. This allows any unauthenticated actor capable of creating a GitHub issue to inject and execute malicious scripts in the security context of the authenticated administrator.
The technical flaw lies in the handling of JSON payloads returned from the GitHub Search API by the client-side JavaScript of the CraftSupport widget. Specifically, the widget utilizes the endpoint 'https://api.github.com/search/issues' to locate relevant issues in the 'craftcms/cms' repository. The returned payload contains an array of issue objects, each containing metadata such as the issue title, status, and URL.
The client-side controller, implemented in 'src/web/assets/craftsupport/src/CraftSupportWidget.js', parses these results and dynamically constructs the HTML structure to display them. To extract the text for display, the application invokes the helper method 'this.getSearchResultText(results[i])', which directly returns the unescaped issue title from the GitHub JSON payload. Rather than treating this string as raw text, the script passes it directly to jQuery functions that manipulate the DOM.
In the vulnerable implementation, the unescaped title is concatenated with structural HTML tags and passed to the jQuery 'html' property within an anchor tag initialization. Because jQuery processes the 'html' property by setting the 'innerHTML' of the element, the browser's HTML parser interprets any embedded markup. An attacker needs only a valid GitHub account to submit a public issue containing JavaScript payloads to the official repository, which then serves as the persistent delivery mechanism.
A secondary injection vector exists within the error rendering path of the 'parseSupportResponse' method. When rendering server-side error responses, the code loops through the returned errors and dynamically appends them using raw string concatenation inside '($('<li>' + error + '</li>'))'. Since the error parameter is treated as HTML rather than plain text, any malicious content within the error payload is similarly parsed and executed in the client's browser context.
To understand the vulnerability, we analyze the raw source code of 'src/web/assets/craftsupport/src/CraftSupportWidget.js' prior to the patch. The following code block demonstrates how the unescaped issue title was rendered directly as HTML:
// Vulnerable Implementation in CraftSupportWidget.js
this.$searchResults.append(
$('<li>').append(
$('<a>', {
href: this.getSearchResultUrl(results[i]),
target: '_blank',
html:
'<span class="status ' +
this.getSearchResultStatus(results[i]) +
'"></span>' +
this.getSearchResultText(results[i]), // Vulnerable: Raw HTML assignment
})
)
);In the snippet above, the 'html' key in the jQuery configuration object instructs the library to assign the concatenated string directly to the target element's 'innerHTML' property. If the value returned by 'this.getSearchResultText(results[i])' contains malicious HTML elements, they are executed immediately. The application makes no attempt to sanitize or escape HTML special characters before this assignment.
The official fix, implemented in commit '6bbb66038a268552180ca5c8eed9f46ea25a4417', introduces a neutralization step using a native sanitization routine. The following code block shows the changes introduced by the development team:
// Patched Implementation in CraftSupportWidget.js
this.$searchResults.append(
$('<li>').append(
$('<a>', {
href: this.getSearchResultUrl(results[i]),
target: '_blank',
html:
'<span class="status ' +
this.getSearchResultStatus(results[i]) +
'"></span>' +
Craft.escapeHtml(this.getSearchResultText(results[i])), // Resolved: Escapes special characters
})
)
);The implementation of 'Craft.escapeHtml()' converts characters like '<', '>', '&', '"', and ''' into their corresponding HTML entity representations. Consequently, the browser renders the markup as inert text instead of parsing it as executable code. Furthermore, the error-rendering routine was refactored to use the jQuery text initialization parameter, which leverages browser text safe assignment methods underneath to ensure protection.
Exploitation of this DOM-based XSS vulnerability follows a multi-stage process that leverages GitHub as an untrusted intermediary. The attack requires no prior authentication or access to the target Craft CMS instance. The adversary must first identify a standard, public GitHub account and use it to register an issue in the official 'craftcms/cms' repository.
The attacker crafts an issue title designed to exploit the DOM rendering logic. A typical payload utilizes standard HTML injection vectors, such as an image tag with an invalid source attribute and an active event handler: Malfunction in Postgres database <img src="x" onerror="alert(document.cookie)">. The attacker submits this issue, and the GitHub API indexes it immediately under the keyword.
The execution phase occurs when an administrator logged into the vulnerable Craft CMS instance accesses the control panel and navigates to the CraftSupport widget. If the administrator enters a search term that matches the attacker's public issue, the widget queries the GitHub API. The API returns the JSON payload containing the poisoned title, which is then processed on the administrator's local browser.
Because the administrator is authenticated within the control panel, the injected script executes with high privileges. The attacker's script can interact with the Craft CMS API to perform unauthorized actions. This includes uploading malicious plugins, modifying system configurations, creating new administrative accounts, or exfiltrating session tokens.
The severity of CVE-2026-55790 is rated as High, with an official CVSS v4.0 base score of 7.4. The attack vector is Network, and the attack complexity is Low, meaning it can be executed reliably. Although it requires a prerequisite and user interaction from the administrator, the privileges required are None for the initial attacker.
The compromise of an administrative session in Craft CMS leads to complete loss of confidentiality and integrity on the affected system. Because the administrator possesses full control over the application environment, any JavaScript executed in their context can invoke administrative actions. This bypasses standard access controls and allows the execution of arbitrary server-side code through the platform's native development utilities.
For instance, the script can issue background AJAX requests to the plugin installation endpoints or the system console. This effectively turns a client-side DOM XSS into a remote code execution vector on the server hosting Craft CMS. Given that many Craft CMS installations manage critical e-commerce database tables or sensitive customer profiles, the exposure of these systems presents substantial organizational risks.
The primary and recommended remediation strategy is to upgrade all vulnerable Craft CMS installations to patched releases. For organizations utilizing Craft CMS v4.x, the platform must be updated to version 4.17.16 or higher. For organizations utilizing Craft CMS v5.x, the system must be updated to version 5.9.23 or higher. These updates contain the commit '6bbb66038a268552180ca5c8eed9f46ea25a4417' which implements proper HTML escaping.
In environments where an immediate upgrade is not feasible, administrators should disable or remove the CraftSupport widget from all dashboards. This can be achieved by removing the widget component from the control panel dashboard configuration or modifying user permissions to prevent access to the support interface. Disabling the widget completely removes the vulnerable client-side code path from the execution flow.
To provide defense-in-depth, security teams should implement a strict Content Security Policy (CSP) for the administrative control panel. The CSP should explicitly disallow the unsafe-inline directive for scripts and restrict executable sources to trusted domains. Furthermore, egress filtering should be configured on the host server to limit the capability of the CMS to communicate with unexpected external domains.
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS v4.0 Score | 7.4 (High) |
| EPSS Score | 0.00311 (Percentile: 22.91%) |
| Impact | Administrative Session Hijacking / Remote Code Execution |
| Exploit Status | PoC / None detected in wild |
| CISA KEV Status | Not Listed |
A security vulnerability in Copier versions 9.5.0 through 9.15.1 allows unauthenticated remote code execution via crafted HTTP requests or local paths containing traversal sequences. The trust-evaluation mechanism compares target repository paths or URLs against trusted prefixes using unnormalized string comparison, while the subsequent fetching mechanism normalizes the path before cloning. Attackers can exploit this asymmetry to bypass security warning prompts and execute arbitrary commands under the local user context.
GeoLens before version 1.2.4 contains multiple critical-tier security vulnerabilities including improper authorization in metadata access, tile cache scope leakage, dataset title enumeration, weak default credentials, and denial of service via STAC POST search.
CVE-2026-55694 is a chained Information Disclosure and Insecure Direct Object Reference (IDOR) vulnerability in Snipe-IT prior to version 8.6.3. The vulnerability allows authenticated, restricted users to completely bypass randomized file-naming security controls, leak the obfuscated filenames of signed End User License Agreements (EULAs), and subsequently download these confidential documents across tenant boundaries.
Snipe-IT is an IT asset/license management system. Prior to 8.6.3, any activated account can request /maintenances/{id} and read maintenance records for assets in the same company without asset or maintenance permission. app/Http/Controllers/MaintenancesController.php show() renders the record without authorize(), while company-scoped route-model binding only prevents access to other companies. Disclosed fields include asset tags, suppliers, purchase costs, notes, and dates. This issue is fixed in version 8.6.3.
A Stored DOM-based Cross-Site Scripting (DOM XSS) vulnerability exists in Snipe-IT versions prior to 8.6.2. The vulnerability occurs when a stored manufacturer or supplier name is converted to CamelCase and rendered within the 'data-selected-count-id' attribute of a table. Client-side JavaScript retrieves this decoded attribute and performs unsafe string concatenation, passing it directly into jQuery's '.after()' method, enabling authenticated attackers to execute arbitrary JavaScript in the victim's session.
CVE-2026-62673 (also known as CVE-2026-62230 and GHSA-vwg3-w8w3-pc79) is a high-severity security bypass vulnerability in the Grav CMS. It permits unauthenticated remote attackers to circumvent directory and file access policies defined in Apache .htaccess. This flaw allows direct retrieval of sensitive configuration files, system-level credentials, and database equivalents from case-insensitive host filesystems.