GHSA-c8jx-96c9-8xrpMedium· 4.3▾ SunlitSurrealDB: Field-level SELECT permissions bypassed via indexed COUNT fast paths
▾ Sunlit zone — Low / medium · no exploitation signal
impact 23.7 · likelihood 0 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
A record user could learn the value of a hidden field by counting how many records match a guess.
When DEFINE FIELD ... PERMISSIONS FOR select WHERE ... hides a field's contents from a caller, and that field is indexed, running SELECT count() FROM t WHERE hidden_field = "guess" GROUP ALL returned a count greater than zero whenever a record actually had that value — even though the caller was never allowed to read the field directly. The query planner used an indexed-COUNT shortcut (Index::Count, IndexCountScan, or the legacy Iterate Index Count / Iterate Index Keys paths) that counts matching index entries and skips the permission check that would normally hide the value. The same query with WITH NOINDEX correctly returned [], confirming the gap.
By repeating the count query with different guesses, an attacker can confirm or recover the contents of any restricted field they could not read through a normal SELECT.
What an attacker can do:
What it can't do:
The legacy planner (surrealdb/core/src/idx/planner/tree.rs) and the streaming planner (surrealdb/core/src/exec/planner/select/mod.rs) now both refuse the indexed fast path when the WHERE / ORDER tree references a field governed by a non-Full SELECT permission:
resolve_indexes skips any B-tree / unique index whose columns are governed by such a permission.cond_touches_restricted_field flag is propagated; eval_count refuses a dedicated Index::Count when set.cond_touches_restricted_select_field, a RestrictedIdiomChecker visitor that matches each idiom against the table's field-permission prefixes (loaded via the plan-time txn), and gates IndexCountScan emission on it.should_check_perms_for_view.Versions 3.1.0 and later are not affected.
Users unable to patch are advised to consider the following workarounds:
DEFINE INDEX on fields whose values are protected by field-level SELECT permissions. The class of attack is specific to the indexed fast paths.SELECT count() … GROUP ALL queries against tables containing field-protected columns.surrealdb < 3.1.0Upgrade to a patched release:
surrealdb 3.1.0Connected by shared product, vendor, weakness, or advisory.
GHSA-8rw6-p7m8-63jpMedium· 6.5SurrealDB: Array element-level (field.*) SELECT permissions leak denied elements to record users
GHSA-fpxg-5xmv-922mMedium· 4.3SurrealDB has bypass of field-level SELECT permissions through JSON Patch `copy` and `move` with empty `from`
GHSA-6wqw-vhfr-9999Medium· 4.3SurrealDB: Authenticated subscribers can read records hidden by SELECT permissions via LIVE subscriptions
GHSA-wp87-mgvq-5j93Medium· 6.5SurrealDB: USE NS/DB implicit creation bypasses DEFINE authorization
CVE-2026-49997Medium· 5.4SurrealDB: Edge PERMISSIONS FOR delete bypassed when a connected node is deleted
GHSA-98fx-66cf-fc7cMedium· 6.5SurrealDB: Scraping a TABLE with no available PERMISSIONS to current auth level