surrealdb: REFERENCE ON DELETE CASCADE bypasses an edge table's PERMISSIONS FOR delete
What fixes it
- 3.3.0surrealdb, rustGitHub
A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.
Description
When a record is deleted, SurrealDB removes the graph edges connected to it. That edge removal is meant to run with the caller's permissions, so an edge table's PERMISSIONS FOR delete clause still applies — deleting an endpoint vertex must not let a caller erase edges they could not delete directly. A previous fix (GHSA-whwg-vh4f-pmmf, patched in 3.1.0) established this for a direct vertex delete.
A second route escaped that guarantee. A DEFINE FIELD ... REFERENCE ON DELETE CASCADE deletes the referencing record when the referenced record is deleted, and it computes that cascading delete with permissions disabled — which is deliberate, so referential integrity can complete regardless of what the caller may do to the referencing record. But permission enforcement was a single frame-wide flag, so the disabled state flowed on into the referencing record's own edge cleanup. If that referencing record was also a graph-edge endpoint, its edges were then removed without consulting the edge table's PERMISSIONS FOR delete clause.
The result was a cross-table authorization bypass: a caller with delete permission on one table could erase edge records in another table, whose PERMISSIONS FOR delete denied them, by deleting an endpoint reached through a REFERENCE ON DELETE CASCADE.
Impact
This affects deployments that combine DEFINE FIELD ... REFERENCE ON DELETE CASCADE with a referencing record that is also a graph-edge endpoint, where the edge table restricts deletion with a PERMISSIONS FOR delete clause.
What an attacker can do:
- With permission only to delete an endpoint vertex, cause the deletion of protected edge records on an edge table whose
PERMISSIONS FOR deleteclause denies them, when the deletion is routed through aREFERENCE ON DELETE CASCADE. - Cause silent, unrecoverable loss of those edge records, which may carry business data.
What it can't do:
- Read the contents of the deleted edges — this is an integrity issue, not disclosure.
- Delete records on tables the caller cannot reach through such a cascade, or cross namespace or database isolation boundaries.
- Escalate to namespace- or root-level privileges. System users (root, namespace, database owners) are governed by their role, not by this flag, and are unaffected.
Patches
The permission context is now split so the referential-integrity bypass no longer reaches the edge cascade. The reference CASCADE still disables permissions for the referencing record's own delete, but the record's edge cleanup runs under the caller's real permission state, so an edge table's PERMISSIONS FOR delete clause is evaluated exactly as it is for a direct DELETE. Edges the caller is not allowed to delete are left in place.
- Versions 3.3.0 and later are not affected by this issue.
Workarounds
Users unable to patch should consider the following workarounds:
- Restrict vertex
DELETEpermission on tables that are reference-cascade targets to principals trusted to delete all connected edge records. - Avoid
REFERENCE ON DELETE CASCADEwhere the referencing record is also a graph-edge endpoint whose edge table relies onPERMISSIONS FOR delete. - Use namespace or database isolation as the primary boundary where edge-level
PERMISSIONSis load-bearing.
References
- SurrealQL Documentation — DEFINE FIELD
- SurrealQL Documentation — Record references
- SurrealQL Documentation — DEFINE TABLE … PERMISSIONS
- SurrealQL Documentation — RELATE statement
fix(doc): keep the reference-CASCADE permission bypass out of the edge cascade(included in SurrealDB 3.3.0)
Acknowledgements
Thank you to Yanhaoxi for reporting this issue.
Text from GitHub Advisory Database
Affected versions 1
- surrealdb, rust>= 3.1.0, < 3.3.0GitHub