CVE-2026-63738 — surrealdb
MEDIUMCVE-2026-63738 is a medium-severity (CVSS 4.3) CWE-863 vulnerability in surrealdb. A fix is available for surrealdb — see the affected versions and patch details below.
SurrealDB: Field-level SELECT permissions bypassed via graph and reference traversals
Exploitation Status
No confirmed exploitation observed yet
- CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-63738.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
CVE-2026-63738 by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.
Where this sits among everything scored
Of 391,411 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.
Real-World Exposure
surrealdbReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects crates.io packages — download data is not available via public APIs for these ecosystems.
Description
A record user could read field values hidden from them by field-level SELECT permissions by reaching the records through a graph-edge (->) or back-reference (<~) traversal instead of a direct SELECT.
When a table was readable at the table level but carried a field hidden by a field-level permission (DEFINE FIELD secret ON knows PERMISSIONS FOR select NONE), a direct SELECT * FROM knows hid secret — but reaching the same records through a traversal that yields full objects — person:bob->(SELECT * FROM knows), person:bob<~(SELECT * FROM comment), or a projected target vertex ->knows->(SELECT * FROM person) — returned it intact.
The root cause: the shared resolve_record_batch helper used by GraphEdgeScan (FullEdge) and ReferenceScan (FullRecord) enforced only the table-level SELECT permission and pushed raw record data, never running the field-level filtering (build_field_state / filter_fields_by_permission) that ordinary table scans and fetch_record apply.
Impact
A record user can read the values of fields hidden by field-level SELECT permissions, on tables they already hold table-level SELECT on, by materialising the records through a graph-edge, back-reference, or target-vertex traversal — recovering the values directly, for every record the traversal returns.
The disclosure is confined to the field-permission layer: it grants no unauthorised cross-table, cross-record, or cross-namespace/database access. The table's own SELECT permission — including any row-level WHERE predicate — is still enforced, so the caller only reaches records they were already entitled to read; only the per-field SELECT filtering within those records is skipped. Root and record-owner sessions are unaffected, and data cannot be modified (confidentiality only).
Table-level enforcement on these traversals landed in 3.1.0 (the fix for GHSA-vjjx-rfw4-rmfc); releases before 3.1.0 additionally exposed whole records on tables the caller could not read, and are covered by that advisory.
Patches
resolve_record_batch (the shared helper that materialises full records for graph and reference traversals) now applies field-level SELECT permissions and read-time COMPUTED fields to each record, matching the regular table-scan and fetch_record paths.
Versions 3.1.5 and later are not affected.
Workarounds
- Force the unaffected legacy executor with
--planner-strategy compute-only(envSURREAL_PLANNER_STRATEGY). - Do not rely on field-level SELECT permissions to hide values on tables reachable as a graph edge, reference target, or traversal vertex; restrict at the table level instead.
- Use namespace / database isolation as the primary boundary where feasible.
Resources
- SurrealQL Documentation — DEFINE FIELD
- SurrealQL Documentation — DEFINE TABLE … PERMISSIONS
- SurrealQL Documentation — Graph relationships
fix(exec): apply field-level SELECT permissions + computed fields when graph/reference traversals materialize full records
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🦀crates.io | surrealdb | ≥ 3.1.0&&< 3.1.5 | 3.1.5cargo update -p surrealdb --precise 3.1.5 |
Affected Products
surrealdbsurrealdbDetection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for surrealdb, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update surrealdb to 3.1.5 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-63738 is resolved across your whole dependency graph.
Workarounds
Put an independent control in front of the weakness: restrict the affected endpoint or interface to trusted networks, require an additional authentication factor or proxy-level check, and invalidate existing sessions and credentials in case the flaw has already been used.
Frequently Asked Questions
Is CVE-2026-63738 in your dependencies?
Find it across crates.io, including transitive dependencies.