See how keystonejs compares to other vendors in security performance
An arbitrary file upload vulnerability in the file upload module of Keystone v4.2.1 allows attackers to execute arbitrary code via a crafted file.
@keystone-6/core is a core package for Keystone 6, a content management system for Node.js. Starting with version 2.2.0 and prior to version 2.3.1, users who expected their multiselect fields to use the field-level access control - if configured - are vulnerable to their field-level access control not being used. List-level access control is not affected. Field-level access control for fields other than multiselect are not affected. Version 2.3.1 contains a fix for this issue. As a workaround, stop using the multiselect field.
Keystone is a headless CMS for Node.js — built with GraphQL and React.@keystone-6/core@3.0.0 || 3.0.1 users that use NODEENV to trigger security-sensitive functionality in their production builds are vulnerable to NODEENV being inlined to "development" for user code, irrespective of what your environment variables. If you do not use NODEENV in your user code to trigger security-sensitive functionality, you are not impacted by this vulnerability. Any dependencies that use NODEENV to trigger particular behaviors (optimizations, security or otherwise) should still respect your environment's configured NODEENV variable. The application's dependencies, as found in nodemodules (including @keystone-6/core), are typically not compiled as part of this process, and thus should be unaffected. We have tested this assumption by verifying that NODEENV=production yarn keystone start still uses secure cookies when using statelessSessions. This vulnerability has been fixed in @keystone-6/core@3.0.2, regression tests have been added for this vulnerability in #8063.
KeystoneJS before 4.0.0-beta.7 allows application-wide CSRF bypass by removing the CSRF parameter and value, aka SecureLayer7 issue number SL7KEYJS03. In other words, it fails to reject requests that lack an x-csrf-token header.
CSV Injection (aka Excel Macro Injection or Formula Injection) exists in admin/server/api/download.js and lib/list/getCSVData.js in KeystoneJS before 4.0.0-beta.7 via a value that is mishandled in a CSV export.
Due to a bug in the the default sign in functionality in the keystone node module before 0.3.16, incomplete email addresses could be matched. A correct password is still required to complete sign in.
Keystone 5 is an open source CMS platform to build Node.js applications. This security advisory relates to a newly discovered capability in our query infrastructure to directly or indirectly expose the values of private fields, bypassing the configured access control. This is an access control related oracle attack in that the attack method guides an attacker during their attempt to reveal information they do not have access to. The complexity of completing the attack is limited by some length-dependent behaviors and the fidelity of the exposed information. Under some circumstances, field values or field value meta data can be determined, despite the field or list having read access control configured. If you use private fields or lists, you may be impacted. No patches exist at this time. There are no workarounds at this time
keystone is vulnerable to Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
A cross-site scripting (XSS) vulnerability exists in fields/types/markdown/MarkdownType.js in KeystoneJS before 4.0.0-beta.7 via the Contact Us feature.
Keystone is a content management system for Node.JS. There is an open redirect in the @keystone-6/auth package versions 7.0.0 and prior, where the redirect leading / filter can be bypassed. Users may be redirected to domains other than the relative host, thereby it might be used by attackers to re-direct users to an unexpected location. To mitigate this issue, one may apply a patch from pull request 8626 or avoid using the @keystone-6/auth package.
Summary When ui.isAccessAllowed is undefined, the adminMeta GraphQL query is publicly accessible, that is to say, no session is required for the query.
This is different to the behaviour of the default AdminUI middleware, which by default will only be publicly accessible if a session strategy is not defined.
Impact This vulnerability does not affect developers using the @keystone-6/auth package, or any users that have written their own ui.isAccessAllowed (that is to say, you are unaffected if ui.isAccessAllowed is defined).
This vulnerability does affect developers who thought that their session strategy will, by default, enforce that adminMeta is inaccessible by the public in accordance with that strategy; akin to the behaviour of the AdminUI middleware.
Patches This vulnerability has been patched in @keystone-6/core version 5.5.1.
Workarounds You can opt to write your own isAccessAllowed to work-around this vulnerability.
References Pull request https://github.com/keystonejs/keystone/pull/8771
Cross-Site Scripting vulnerability in KeystoneJS before 4.0.0-beta.7 allows remote authenticated administrators to inject arbitrary web script or HTML via the "content brief" or "content extended" field, a different vulnerability than CVE-2017-15878.
Summary {field}.isFilterable access control can be bypassed in update and delete mutations by adding additional unique filters. These filters can be used as an oracle to probe the existence or value of otherwise unreadable fields.
Specifically, when a mutation includes a where clause with multiple unique filters (e.g. id and email), Keystone will attempt to match records even if filtering by the latter fields would normally be rejected by field.isFilterable or list.defaultIsFilterable. This can allow malicious actors to infer the presence of a particular field value when a filter is successful in returning a result.
Impact This affects any project relying on the default or dynamic isFilterable behaviour (at the list or field level) to prevent external users from using the filtering of fields as a discovery mechanism. While this access control is respected during findMany operations, it was not completely enforced during update and delete mutations when accepting more than one unique where values in filters.
This has no impact on projects using isFilterable: false or defaultIsFilterable: false for sensitive fields, or if you have otherwise omitted filtering by these fields from your GraphQL schema. (See workarounds)
Patches This issue has been patched in @keystone-6/core version 6.5.0.
Workarounds To mitigate this issue in older versions where patching is not a viable pathway.
- Set isFilterable: false statically for relevant fields to prevent filtering by them earlier in the access control pipeline (that is, don't use functions) - Set {field}.graphql.omit.read: true for relevant fields, which implicitly removes filtering by these fields your GraphQL schema - Deny update and delete operations for the relevant lists completely (e.g list({ access: { operation: { update: false, delete: false } }, ... }))
Summary {field}.isFilterable access control can be bypassed in findMany queries by passing a cursor. This can be used to confirm the existence of records by protected field values.
The fix for CVE-2025-46720 (field-level isFilterable bypass for update and delete mutations) added checks to the where parameter in update and delete mutations however the cursor parameter in findMany was not patched and accepts the same UniqueWhere input type.
Impact This affects any project relying on isFilterable behaviour (at the list or field level) to prevent external users from using the filtering of fields as a discovery mechanism. isFilterable access control using a function can be bypassed by using the cursor input.
This has no impact on projects using isFilterable: false or defaultIsFilterable: false for sensitive fields, or if you have otherwise omitted filtering by these fields from your GraphQL schema. (See workarounds)
Patches This issue has been patched in @keystone-6/core version 6.5.2.
Workarounds To mitigate this issue in older versions where patching is not a viable pathway.
- Set {field}.isFilterable: false statically for relevant fields to prevent filtering by them earlier in the access control pipeline (that is, don't use functions) - Set {field}.graphql.omit.read: true for relevant fields, which implicitly removes filtering by these fields your GraphQL schema