Open actionable advisories and recorded vendor fixes. This public package view has no inventory attached and cannot establish whether your deployment is affected. A vendor fix never resolves your finding; verify your installed version and the source guidance.
Open advisories
118 actionable advisories, newest first. Withdrawn advisories and news are excluded. Coverage is partial.
Craft CMS passkey login accepts WebAuthn requestOptions from the unauthenticated login request body and does not persist the updated credential counter returned by the WebAuthn assertion validator. A captured passkey login request body can therefore be replayed because the old challenge is accepted again, and the stored credential counter remains stale. Craft CMS 5.10.3 and current 5.x HEAD accept PublicKeyCredentialRequestOptions from the unauthenticated users/login-with-passkey request body and do not persist the updated PublicKeyCredentialSource returned/mutated by web-auth/webauthn-lib after assertion validation. As a result, a captured passkey login request body is not one-time-use. Reposting the same requestOptions and response can result in validation against the same stale credential counter and create another Craft session for that user. This weakens passkeys from a fresh, server-challenged authentication ceremony into a replayable bearer artifact if one successful assertion…
Recommended action: Upgrade to 5.10.5 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The create() Twig function (introduced in 5.9.0) allows instantiation of arbitrary PHP classes from template code, restricted only by a 5-entry blocklist. SplFileObject is not in the blocklist, enabling arbitrary file read, including .env (security key, DB credentials) and the passwd file from non-sandboxed Twig template contexts, such as entry type title formats and URI formats. The sandbox correctly blocks create() in system email templates, so this finding applies only to admin-configured, non-sandboxed contexts that require allowAdminChanges=true. Prerequisites - Admin access to the Craft control panel - allowAdminChanges must be true (default in dev/staging, recommended false in production) - Admin must be able to edit entry type settings (title format, URI format) - Any user who subsequently creates an entry in the affected section triggers the file read Limitations - Requires admin-level access: not exploitable by low-privilege users - allowAdminChanges must be true:…
Recommended action: Upgrade to 5.10.6 or 4.18.2 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Environment variables and secrets are interpolated into a Twig template even when the Twig sandbox is enabled, allowing them to be leaked by an authenticated attacker. The Craft vulnerability CVE-2026-31857 was only patched by applying sandboxed Twig templating. This theoretically protects Craft CMS against RCE attacks, provided the sandbox is enabled and secure, with no known bypasses. However, the same request parameter elementId, which allows for sandboxed Twig templates to be rendered, also includes functionality that interpolates referenced environment variables. If the parameter includes a string of the form ${ENVVAR} then the string is replaced with the environment variable or secret from a secrets file with that name. Afterward, the string is rendered as a Twig template. If the sandbox is disabled, Twig templates can already gain RCE or access environment variables using the getenv function. Sandboxed Twig templates should not have this access, but now do thanks to this…
Recommended action: Upgrade to 5.10.6 or 4.18.2 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
A control-panel user who holds only the viewCategories permission for a category group (and not saveCategories) can permanently modify that group's category structure — reordering and re-parenting categories via the structures/move-element action. A read-time authorization grant that a write endpoint later trusts. For categories, the structureEditable flag is computed from the view permission (src/elements/Category.php:205) instead of the save permission (entries correctly use saveEntries — src/elements/Entry.php:341). When the read-only category index renders, craft\base\Element::indexHtml() calls Craft::$app-getSession()-authorize('editStructure:<structureId'); StructuresController then authorizes the structure-mutating action solely on that session grant, with no canSave re-check. Verified on Craft CMS 5.10.5. Same class as the moderate-severity authorization bypasses fixed in 5.10.3 and 5.10.5; this is a distinct, unpatched instance. Impact A low-privileged, authenticated user…
Recommended action: Upgrade to 5.10.6 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
ChartsController::actionGetNewUsersData() at /actions/charts/get-new-users-data is missing a requirePermission('viewUsers') authorization check. Any authenticated control panel user, regardless of permissions beyond accessCp, can POST to this endpoint to receive time-series user registration counts for the entire site or for an arbitrary user group ID. The viewUsers permission is consistently required throughout the control panel before exposing user-related data, but this action enforces only the base accessCp check inherited from the framework. Each call returns the total count of users who joined the specified group in the requested period. Impact Any control panel user with only accessCp permission can obtain the total number of registered users and their registration date distribution across any time window. In installations with multiple editor roles, this allows a low-privilege control panel user to infer user group sizes and registration trends that would normally require the…
Recommended action: Upgrade to 5.10.3 or 4.18.1 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The ensurePathIsContained function of the Local file system class is theoretically vulnerable to path traversal, although no exploitable scenario has been discovered. When a file is read, an Asset object uses the getFileStream method of the Volume where the asset file is stored, which in turn uses the getFileStream method of the file system class used by that Volume. For the Local file system, this function returns a stream to a file on the local disk after verifying and creating the correct file path. The file path is constructed by first validating the path and then adding a prefix to the validated and normalized path. The prefix is the path to the local directory that houses the particular volume. The order of operations matters here: first, a validation step, afterward a normalization step, and finally the construction of the resulting file path. This opens the possibility of a desanitization-style vulnerability, where the normalization invalidates the assumptions made by the…
Recommended action: Upgrade to 5.10.6 or 4.18.2 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The control-panel helper that renders element chip/card labels writes an element's draftName into the page without HTML-encoding it, while the surrounding path segments are encoded. A low-privilege control-panel user who can create a draft of an element (for example, an entry) controls the draft name, so they can store an XSS payload that executes in the browser of any other control-panel user who is shown that element’s chip or card (element indexes with drafts visible, relation and element-selection fields that reference the element, and the drafts list). This allows a low-privilege author to run JavaScript in an administrator’s authenticated session and take over the control panel. It is the same output-encoding class as the recently fixed GHSA-xrqc-p465-2xvg (Structure entry title) and GHSA-3x4w-mxpf-fhqq (revision context menu), which encoded other user-controlled titles but not the draft name. Prerequisites - A control-panel account with permission to edit entries in at least…
Recommended action: Upgrade to 5.10.8 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The vulnerability allows any authenticated user to change their own password without providing the current password or having an active elevated session. It also allows the attacker to change other users’ passwords if the attacker’s account has edit users permission (which doesn’t allow changing others’ passwords) and lacks Administrate users permission (which is required to change others’ passwords). The vulnerability exists in the elements/save action when saving a User element. The UserPasswordValidator applies only a safe validator to the newPassword field without an on scenario restriction. This makes newPassword mass-assignable during the generic element save flow, completely bypassing the dedicated users/set-password action that enforces elevated session verification. An attacker with any authenticated session (whether it’s hijacked or a normal / low-privileged user) can change their own password, and potentially take over administrator accounts. Required Permissions - Access…
Recommended action: Upgrade to 5.10.8 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The Twig sandbox mechanism in Craft CMS is configured to allow dangerous functionality from the Yii framework, leading to authenticated RCE in a manner similar to previously disclosed vulnerabilities. The Twig sandbox in Craft CMS works by implementing Twig's SecurityPolicyInterface. The resulting SecurityPolicy class implements the checkMethodAllowed and checkPropertyAllowed methods of the interface. The implementations compare whether the called method or property is in a configured allowlist or is marked with the AllowedInSandbox attribute. Additionally, SecurityPolicy allows the allowlisting of whole classes, which is shorthand for allowing all methods and properties of that class to be called. Both the allowlists for tags, filters, variables, methods, properties, and classes, as well as the AllowedInSandbox attribute mechanism, are preconfigured by Craft CMS to allow user-defined templates to use core functionality unimpeded. Additionally, Craft CMS project developers can add…
Recommended action: Upgrade to 5.10.7 or 4.18.3 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The reorder-sets action in Craft CMS’s GlobalsController is missing the requireAdmin() check that the adjacent save-set and delete-set actions both enforce. Any authenticated control panel user can POST to /actions/globals/reorder-sets and permanently reorder all global sets in the project config, regardless of whether they have admin access. The reordering is written through to the project config and persists across requests. Description GlobalsController exposes three administrative actions for managing global set structure. Two of them gate on admin status; the third does not. Prerequisites - A Craft CMS instance with at least two global sets and a non-admin control panel user account. Impact A non-admin control panel user can reorder all global sets. While this does not expose or modify content, reordering global sets modifies the project config -- a versioned artifact that is typically committed to source control and deployed across environments. An attacker can create noise in…
Recommended action: Upgrade to 5.10.3 or 4.18.1 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Craft CMS has an authenticated remote code execution issue in the control panel element-search condition handling. Craft cleans the outer request-controlled condition array with Component::cleanseConfig(), but Conditions::createCondition() later decodes and merges the JSON string in condition.config without re-running cleanseConfig() on the decoded/merged configuration. Because condition.config is a JSON string during the first cleanse, Yii special config keys such as as ... and on ... can be hidden inside it. After JSON decoding, those keys reach FieldLayout object creation and are interpreted by Yii as behavior/event configuration. The RCE is semi-blind: the trigger endpoint returns a normal JSON response, and the command output is verified via a server-side file-write side effect retrieved in a subsequent request. Preconditions - The attacker needs an authenticated Craft control panel session. - A valid CSRF token is required. Impact An authenticated control panel user can inject…
Recommended action: Upgrade to 5.10.6 or 4.18.2 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The actionRenderCardPreview() method in FieldsController passes the fieldLayoutConfig POST parameter directly to Fields::createLayout() without calling Component::cleanseConfig(). This allows Yii2 event handler injection via on eventName keys in the config array, leading to arbitrary code execution. This is the same vulnerability pattern that was fixed in GHSA-4484-8v2f-5748 (same file, fldComponent method correctly uses cleanseConfig), GHSA-qx2q-q59v-wf3j (EntryTypesController), and GHSA-2fph-6v5w-89hh (ElementIndexesController). PoC As an admin user with a valid session: When the FieldLayout object is constructed, Yii2 processes the on init key as an event handler registration. During Component::init(), the init event is triggered, calling phpinfo(). The phpinfo output (which includes environment variables, potentially containing database credentials and CRAFTSECURITYKEY) will appear in the response. Impact An authenticated admin can achieve RCE through Yii2 event handler…
Recommended action: Upgrade to 5.9.14 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
An authenticated path traversal in assets/icon allows local SVG file read by passing traversal sequences in the extension parameter. The issue is caused by file existence checks happening before extension validation. Details The endpoint: - src/controllers/AssetsController.php:1115-1123 - actionIcon(string $extension) calls Assets::iconPath($extension) and returns sendFile($path, ...). In Assets::iconPath(): - Path is built from user-controlled extension: - src/helpers/Assets.php:906-909 - If fileexists($path) is true, path is returned immediately: - src/helpers/Assets.php:910-912 Validation exists in Assets::iconSvg(): - pregmatch('/^\w+$/', $extension) - src/helpers/Assets.php:927-931 However, that validation is only reached if iconPath() does not find a file. So traversal payloads that resolve to existing .svg files bypass validation and are served by sendFile(). Impact - Authenticated users can read local .svg files accessible to the application process. References -…
Recommended action: Upgrade to 5.9.13 or 4.17.7 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Requirements: Control panel access Permissions to edit an entry Details Control panel users with the ability to edit entries can execute unsandboxed Twig code via the HTTP Referrer header. The issue happens when a user is saving entries. Strings for a signed redirect URL are being compiled as a Twig template via renderObjectTemplate(), and while a sandboxed alternative already exists (renderSandboxedObjectTemplate()), it is not used in this case. This signed URL can be specified by users, as it is reflected in the “Referer” HTTP request header, which is under attacker control. This has been fixed in Craft 5.10.0. Affected users should update to that version or higher to get the fix. Resources https://github.com/craftcms/cms/pull/18680
Recommended action: Upgrade to 5.10.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The dataUrl() Twig function is included in Craft’s Twig sandbox allowlist, allowing any control panel user granted the utility:system-messages permission to embed a file-reading payload into system email templates. When those emails are sent, the server reads the target file and returns its contents as a base64-encoded data URL embedded in the email body. The .env file, which typically contains the database password, CRAFTSECURITYKEY, and third-party API keys, passes all of Craft’s existing dataUrl() protection checks and is fully exfiltrated. Obtaining CRAFTSECURITYKEY enables an attacker to forge session tokens and escalate to full admin account takeover. Details Affected versions: Craft CMS 4.x, 5.x (confirmed against 5.9.19) The vulnerability arises from the combination of three code facts: 1. dataUrl is in the Twig sandbox allowlist src/config/twig-sandbox.php, line 115: php'allowedFunctions' = [ ... 'dataUrl', // ← allows file reading inside sandboxed templates ... ], 2.…
Recommended action: Upgrade to 5.10.0 or 4.18.0 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
A user with Control Panel access but without permission to view a target private asset can call assets/preview-thumb and receive preview HTML that contains a signed fallback transform link for that private asset. Details Root-cause analysis: 1. The endpoint accepts an attacker-controlled assetId. 2. Asset is resolved, and thumbnail HTML is returned. 3. No explicit asset-view permission check is performed before preview generation. Impact Type: 1. Missing authorization 2. Unauthorized preview-link disclosure Affected deployments: 1. Craft sites with control panel users who have partial permissions and private assets. Security consequence: 1. A control panel user without asset-view permission can still obtain signed preview transform link data for private assets. 2. This may increase private asset exposure risk depending on deployment and endpoint chaining. Resources https://github.com/craftcms/cms/commit/d30df3112220db1ffd6726a3ed11857014c7fb27
Recommended action: Upgrade to 5.9.14 or 4.17.8 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
We have identified an authorization issue in Craft CMS where a forced folder move can delete a conflicting destination folder without destination delete permission. Description Craft CMS’s craft\\controllers\\AssetsController::actionMoveFolder() supports moving an asset folder into a destination parent folder. If a folder with the same name already exists at the destination, the action can be called with force=true to overwrite the destination. The permission checks for this action allow: - deleteAssets:<sourceVolumeUid for the folder being moved - createFolders:<destVolumeUid for the destination parent folder - saveAssets:<destVolumeUid for the destination parent folder The action does not require deleteAssets on the destination volume or destination conflict folder. When force=true and a name conflict exists, the code deletes the destination folder to resolve the conflict. src/controllers/AssetsController.php:L751-L753 Indexed destination conflicts are deleted via the Assets…
Recommended action: Upgrade to 5.9.21 or 4.17.14 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
There is a mass-assignment flaw in the bulk-duplicate element action. Alice, holding only the permission to duplicate an entry she owns, submits an arbitrary id through the newAttributes request parameter. The duplication routine overrides its own id = null reset with that value and writes Alice’s attributes into Bob’s existing entry row. Details ElementsController::beforeAction() (src/controllers/ElementsController.php:119-124) pulls the request body into $this-attributes and rejects requests that ship an id or canonicalId key at the top level: The check inspects only the top-level payload. actionBulkDuplicate() (src/controllers/ElementsController.php:1708-1749) reads a separate newAttributes array and passes it straight through to the service layer: Elements::duplicateElement() (src/services/Elements.php:1814-1840) clones the source element, sets id to null, and then hands the attacker's array to Craft::configure(): Craft::configure() overwrites the reset id with any…
Recommended action: Upgrade to 5.9.21 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
AssetsController::actionDeleteFolder() only requires the deleteAssets:<volume-uid permission for the target folder. It never enforces deletePeerAssets:<volume-uid, even though Assets::deleteFoldersByIds() cascades deletion to every descendant folder and every asset inside, regardless of who uploaded them. A low-privilege user who has been granted folder-management rights on a shared volume can therefore destroy assets uploaded by other users (peer assets), bypassing the per-asset peer-permission check that the sibling actionDeleteAsset endpoint correctly applies. This is the same bug class that was just fixed in actionMoveFolder as GHSA-3w32-23wj-rxg3 (commit 05c2042, Apr 23 2026); the fix added requireVolumePermissionByFolder('deletePeerAssets', …) and savePeerAssets checks to the move endpoint but did not propagate to the delete-folder endpoint. Details src/controllers/AssetsController.php:552-569: requireVolumePermissionByFolder()…
Recommended action: Upgrade to 5.9.22 or 4.17.15 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
We have identified an authorization issue in Craft CMS AssetsController::actionReplaceFile that can delete a source asset without source delete permission by supplying both assetId and sourceAssetId. Description Craft CMS’s craft\\controllers\\AssetsController::actionReplaceFile() supports replacing a target asset file using another existing asset as the source. The action loads: - $assetToReplace from assetId - $sourceAsset from sourceAssetId It then enforces replace permissions using ($assetToReplace ?: $sourceAsset). When both IDs are provided, this expression resolves to the target asset so no permission check is performed against the source asset volume. src/controllers/AssetsController.php:L433-L434 In the branch where both assets are present, Craft copies the source file into the target and then deletes the source asset. There is no check for deleteAssets:<sourceVolumeUid or deletePeerAssets:<sourceVolumeUid for the source asset before deletion.…
Recommended action: Upgrade to 5.9.21 or 4.17.14 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The EntriesController::actionMoveToSection() endpoint checks only whether the current user can view the destination section, but it does not require permission to save entries into that section. A low-privileged authenticated control-panel user who can move an entry out of its current section can therefore move that entry into a different section where they have read access but no write access. Details The vulnerable route is implemented in EntriesController.php:465: The destination check is only viewEntries:$section-uid . The source-entry gate is Entry::canMove(), which verifies whether the user can move the existing entry based on the source section: This closes the exploit chain: 1. External source: authenticated CP request to entries/move-to-section. 2. Missing authorization check: destination section requires only viewEntries, not saveEntries. 3. Privileged sink: moveEntryToSection() rewrites sectionId and saves the entry into the unauthorized section. Preconditions…
Recommended action: Upgrade to 5.9.21 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
EntriesController::actionSaveEntry() performs entry-edit permission checks before request-controlled author changes are applied to the model. The subsequent author mutation path accepts attacker-supplied authors / author parameters and allows the change when the current user is one of the old authors. Because the controller does not re-run authorization after mutating the author list, a low-privileged user can reassign an entry’s authorship to another user without holding the dedicated peer-author-change permission. Details The control flow begins in EntriesController.php:249. actionSaveEntry() loads the entry and enforces edit permissions before calling populateEntryModel(): The attacker-controlled source is in EntriesController.php:588: Entry::setAttributesFromRequest() in Entry.php:1124 extracts the new author IDs and applies them if canChangeAuthor() returns true: canChangeAuthor() at Entry.php:2789 allows the author change when the current user can view peer entries and…
Recommended action: Upgrade to 5.9.21 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
1. Overview Craft CMS is vulnerable to Server-Side Request Forgery (SSRF) and Arbitrary JavaScript Injection through the /actions/app/resource-js endpoint. By exploiting the default permissive trustedHosts configuration, an attacker can poison the Host or X-Forwarded-Host header to manipulate the application’s $baseUrl. This bypasses the endpoint’s internal URL validation, forcing the backend Guzzle client to fetch a malicious payload from an attacker-controlled server and reflect it to the client with a Content-Type: application/javascript header. 2. Vulnerability Mechanism (Root Cause) The vulnerability manifests when assetManager.cacheSourcePaths is set to false. The attack chain relies on three structural flaws and insecure defaults: - A. Default Proxy Trust (trustedHosts): Craft’s default GeneralConfig::$trustedHosts is set to ['any']. This allows an attacker to bypass front-end web server (Nginx/Apache) strict Host header validations by simply injecting an X-Forwarded-Host…
Recommended action: Upgrade to 5.10 or 4.18 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
AssetsController::actionShowInFolder() fetches an asset by ID and returns its filename and complete folder hierarchy (including volume handle, volume UID, folder names, folder UIDs, and folder URI paths) without checking whether the requesting user has viewAssets or viewPeerAssets permission on the asset’s volume. Any authenticated CP user — even one with zero volume permissions — can enumerate asset filenames and the full folder structure of any volume by supplying arbitrary asset IDs. This follows the exact same incomplete-patch pattern as four GHSAs merged on 2026-02-25 (GHSA-x76w-8c62-48mg, GHSA-vgjg-248p-rfm2, GHSA-5pgf-h923-m958, GHSA-3pvf-vxrv-hh9c), all of which added requireVolumePermissionByAsset() + requirePeerVolumePermissionByAsset() to sibling AssetsController actions. The actionShowInFolder method was introduced thirteen days before the patch wave and was not included in it. Details The vulnerability is in src/controllers/AssetsController.php at line 1437. The…
Recommended action: Upgrade to 5.9.18 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
We identified a vulnerability in the latest version of Craft CMS which contains an input-handling flaw in a Yii object creation path that let any authenticated user inject malicious configuration and execute arbitrary commands on the server. Yii’s dynamic object configuration, as implemented in Craft CMS, is a feature that lets the application build parts of itself from a settings list. This is largely a continuation of https://github.com/craftcms/cms/security/advisories/GHSA-255j-qw47-wjh5, but through a different path that was not mitigated in the original. The request-controlled condition field layouts data is converted into a live FieldLayout object without a Component::cleanseConfig() boundary. Because Craft configures models before parent::construct(), attacker-controlled special config keys can take effect during object creation, and FieldLayout initialization then triggers a same-request event. This appears to be another variant of the recent object-config /…
Recommended action: Upgrade to 5.9.18 or 4.17.12 by release line, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.