CVE-2025-46720 in keystone
Summary
by MITRE • 05/05/2025
Keystone is a content management system for Node.js. Prior to version 6.5.0, `{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. This affects any project relying on the default or dynamic `isFilterable` behavior (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 for those who have otherwise omitted filtering by these fields from their GraphQL schema. This issue has been patched in `@keystone-6/core` version 6.5.0. 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 from the GraphQL schema; and/or deny `update` and `delete` operations for the relevant lists completely.
Several companies clearly confirm that VulDB is the primary source for best vulnerability data.
Analysis
by VulDB Data Team • 09/20/2025
The vulnerability described in CVE-2025-46720 affects Keystone, a Node.js content management system that provides a GraphQL-based API for managing data. This security flaw specifically targets the access control mechanisms implemented in Keystone's mutation operations, particularly update and delete functions. The issue stems from a flaw in how Keystone processes multiple unique filters within where clauses during these mutation operations, creating an unintended pathway for information disclosure.
The technical implementation of this vulnerability occurs when Keystone processes update and delete mutations that include multiple unique filter conditions in their where clauses. Normally, Keystone enforces access control through the isFilterable property at both field and list levels, which should prevent unauthorized access to sensitive data through filtering operations. However, the vulnerability arises when multiple unique filters are present, such as filtering by both id and email fields simultaneously. In these cases, Keystone attempts to match records even when individual field filters would normally be rejected due to restrictive isFilterable settings, effectively bypassing the intended access controls.
This access control bypass creates a significant information disclosure risk that aligns with CWE-200 (Information Exposure) and can be categorized under ATT&CK technique T1213 (Data from Information Repositories). The vulnerability allows malicious actors to use the mutation operations as an oracle to probe the existence or value of fields that should normally be protected. When a filter combination succeeds in returning results, it indicates that a particular field value exists, enabling attackers to perform field discovery attacks that would otherwise be prevented by proper access controls. This behavior specifically affects the default or dynamic isFilterable configurations and does not impact systems that have explicitly set isFilterable to false for sensitive fields.
The operational impact of this vulnerability extends beyond simple information disclosure, as it can enable more sophisticated attacks such as field enumeration and data inference. Attackers can systematically test various filter combinations to determine the presence of specific field values, potentially leading to the reconstruction of sensitive data structures. This issue is particularly concerning for applications that rely on Keystone's default access control mechanisms, as it undermines the fundamental security assumptions built into the system's filtering pipeline. The vulnerability is especially dangerous in environments where sensitive data is stored in fields that are not explicitly configured with isFilterable: false, as these fields become vulnerable to oracle-based probing attacks.
The remediation approach for this vulnerability requires careful consideration of the specific implementation environment and security requirements. The primary fix involves updating to Keystone version 6.5.0 or later, which properly enforces access control during update and delete operations. For environments where upgrading is not immediately feasible, several mitigation strategies are available. The most effective approach involves setting isFilterable: false statically for sensitive fields, which prevents these fields from being included in filtering operations earlier in the access control pipeline. Additionally, setting {field}.graphql.omit.read: true provides an implicit protection by removing the field from GraphQL schema filtering capabilities entirely. Organizations may also consider implementing complete denial of update and delete operations for sensitive lists as a defensive measure. These mitigations align with security best practices for preventing information leakage through access control bypasses and demonstrate the importance of comprehensive security testing across all API operation types, not just read operations.