Open actionable advisories and recorded vendor fixes. This public package view has no inventory attached and cannot establish whether your deployment is affected. A vendor fix never resolves your finding; verify your installed version and the source guidance.
Open advisories
54 actionable advisories, newest first. Withdrawn advisories and news are excluded. Coverage is partial.
An authenticated user scoped to one namespace/database could invoke a custom API (DEFINE API) belonging to a different namespace/database, reaching another tenant's endpoint. The route /api/{namespace}/{database}/{endpoint} took the namespace and database from the URL and applied them to the caller's session before the endpoint was looked up or run, without checking that the caller's authenticated scope covered them. Because a custom API handler runs with permissions disabled (definer's rights), the endpoint's own PERMISSIONS clause was the only gate — open to everyone for a PERMISSIONS FULL endpoint. The api::invoke() function was affected the same way, resolving against the session's selected namespace/database (settable via the surreal-ns / surreal-db headers or USE). Impact What an attacker can do: - With valid credentials for any one namespace/database (a VIEWER is enough), invoke a custom API in another namespace/database by naming the victim scope in the URL. - Read data that…
Recommended action: Upgrade to 3.2.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
A SELECT permission defined on an array element (DEFINE FIELD field. … PERMISSIONS FOR select …) is not enforced correctly for RECORD users. Instead of hiding the denied elements, the query leaks a subset of them: a deny-all returns the odd-indexed elements, and a per-element predicate keeps and drops the wrong ones. The filter removed each denied element by index while walking the array forwards. Because removing an element shifts every later index down, each cut invalidated the indices still pending in the loop, leaving denied elements behind. Field-level permissions are enforced correctly; only the element (field.) level is affected, and only for record users — root and record-owner sessions are not. Impact What an attacker can do: - As a record (scope) user, read array elements that an element-level (field.) SELECT permission should hide, on any table they can already SELECT. - Recover denied elements through both a deny-all and a WHERE predicate — the wrong elements are selected…
Recommended action: Upgrade to 3.1.4 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Default table permissions in SurrealDB were FULL instead of NONE. This would lead to tables having FULL permissions for SELECT, CREATE, UPDATE and DELETE unless some other permissions were specified via the PERMISSIONS clause. We have decided to treat this behaviour as a vulnerability due to its security implications, especially considering the lack of specific documentation and potential for confusion due to the INFO FOR DB statement previously not displaying default permissions. Treating it as a bug fix provides justification for a change in default behavior outside of a major release. Impact Any client authorized to query data in a SurrealDB instance will have full access to any tables that were defined with no explicit permissions and that are within its authorization scope (i.e. namespace or database), including creating, reading, updating and deleting data. This is specially relevant for SurrealDB instances allowing guest access with publicly exposed interfaces (e.g. HTTP REST…
Recommended action: Upgrade to 1.0.1 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
In SurrealDB, records can be connected as a graph: a RELATE statement creates an edge record between two node records. If either endpoint node is deleted, SurrealDB automatically removes the edge row to keep the graph consistent. A user with permission to delete a node could also delete the edges connected to that node, even when the edge table's PERMISSIONS FOR delete clause should have stopped them. The automatic edge removal (Document::purgeedges) ran with permissions disabled (opt.clone().withperms(false)), so the edge table's PERMISSIONS FOR delete and PERMISSIONS FOR select clauses were never consulted. The removal step could also observe edge state that the edge's SELECT clause should have hidden. Impact What an attacker can do: - Delete any edge connected to a node they can delete, regardless of the edge table's PERMISSIONS FOR delete clause. - Observe edge contents that PERMISSIONS FOR select should have hidden, as a side effect of the same edge-removal step. What it can't…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
When a user configures ALGORITHM ES512 for any JWT access method (DEFINE ACCESS ... TYPE JWT ALGORITHM ES512), SurrealDB silently substitutes ES384 at all four internal algorithm conversion points. This occurs because the underlying jsonwebtoken crate (v10.x) does not include an ES512 algorithm variant, so the mapping defaults to ES384 without raising an error, warning, or log message. Users who provide the correct P-521 key type for ES512 will experience authentication handshake failures due to the curve mismatch with ES384 (which expects P-384). Impact Authentication handshake failures when using ES512 with the correct P-521 key type, and when tokens are verified by external systems expecting real ES512 signatures. This vulnerability cannot be exploited to forge tokens or compromise the integrity or confidentiality of data handled by SurrealDB, as ES384 remains cryptographically strong. Patches Versions prior to SurrealDB v3.1.0 are vulnerable. The patches for SurrealDB v3.1.0…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
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`. Impact What an attacker can do: - Confirm or…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
An anonymous caller could create new namespaces and databases on a running SurrealDB instance without holding `DEFINE NAMESPACE` or `DEFINE DATABASE` permission. `USE NS ` and `USE DB ` automatically create the target when it does not exist. The three places `USE` is handled — the RPC `use` method, `Datastore::process_use`, and the SurrealQL executor — did not check whether the caller was allowed to create the resource. Under default capabilities any session reached this path, including an unauthenticated guest. Impact What an attacker can do: - Create new namespaces and databases without `DEFINE NAMESPACE` / `DEFINE DATABASE` permission. An unauthenticated guest is enough under default capabilities. - Recreate a parent namespace that an operator deliberately dropped, using a stale namespace-Editor token, by running `USE NS DB anything`. - Exhaust catalog storage by repeatedly creating new resources. What it can't do: - Read or modify data inside any pre-existing…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
SurrealDB offers http:: functions that can access external network endpoints, with the --allow-net and --deny-net capabilities used to restrict the set of network targets that can be reached. An authenticated user of SurrealDB can bypass a port-scoped --deny-net <host:<port rule by chaining an HTTP redirect: the initial request goes to an --allow-net-permitted hostname, the response's 3xx Location header points at the denied host:port, and the redirect is followed even though the destination was explicitly denied. The root cause is in the redirect policy applied to outbound HTTP requests (surrealdb/core/src/fnc/util/http/mod.rs): the NetTarget for the redirect destination is built from url.hoststr() alone and url.port() is dropped. The capability matcher (surrealdb/core/src/dbs/capabilities.rs:259-264) refuses to match a port-bearing rule against a port-stripped target (Self::Host(host, Some(port)) = match tgt { = false }), so the operator's port-scoped deny rule silently does not…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
A record user could read records the table's SELECT permission expression should have hidden, when that expression referenced `$value`, `$before`, `$after`, or `$event`. Binding a chosen value to that name before registering a `LIVE SELECT` caused notifications to evaluate the permission against the attacker's input instead of the real document. Impact A record user binds a value to `$value`, `$before`, `$after`, or `$event` (e.g. `LET $value = [$auth.id]`) and registers `LIVE SELECT * FROM person`. The captured value shadows the real document at notification time, so a SELECT permission like `WHERE $auth.id.id() IN $value` passes for every record on the table — the subscriber receives notifications for records they should not see. Read-only impact, bounded to one table. Permission expressions that reference only field names, `$auth`, or `$session` are unaffected. Patches A patch has been introduced that re-orders the LIVE notification parameter binding so captured user…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
`RELATE` creates an edge record between two existing records, and SurrealDB enforces the `CREATE` permission on the edge table for this operation. When the statement included a `SET id = edge:existing` clause, however, the new edge's id ended up pointing at an record that was already in storage. Rather than failing because the target already existed — which is what a create operation should do — the storage layer silently overwrote the existing edge. A caller with `CREATE` permission could therefore replace any existing edge on the table, even without `UPDATE` permission for that record. Impact An authenticated user with `CREATE` permission on an edge table could overwrite any existing record on that table — including edges they had no `UPDATE` permission for — by issuing a `RELATE` whose `SET id = …` resolved to the target record's id. The attack is integrity-only. Patches A patch has been introduced that adds an explicit `Statement::Relate` arm using `put_record` instead of…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
SurrealDB lets callers modify records using JSON Patch operations via the UPDATE … PATCH statement (and SDK equivalents such as db.patch()). One of those operations is copy, which duplicates one field's value into another field of the same record. A PATCH with an empty from — for example, UPDATE thing:1 PATCH [{ op: 'copy', from: '', path: '/leak' }] — was treated as "copy the entire record" and duplicated every field, including fields the caller has no permission to read, into the destination field the caller chose. The permission filter that hides protected field values from the response only knew to hide the original protected field names, not the new destinations, so the protected values were returned to the caller intact under the new field name. Impact An authenticated user with permission to issue UPDATE … PATCH against a record could read the values of any field on that record, regardless of field-level PERMISSIONS FOR select restrictions. The leak is confidentiality-only,…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
A record user with UPDATE access could read field values that field-level SELECT permissions hid from them. Arithmetic operators and extend embedded the raw operand into their error messages, and UPDATE permission checks evaluate against the unreduced document — so triggering such an error against a hidden field returned its value in the resulting error. Impact A record user issues an UPDATE that performs an incompatible operation against a hidden field — e.g. UPDATE person:me SET probe = email + 1 when email is a string — and reads the value from the returned error (Tried to compute "alice@example.com" + 1 …). One field per operation, but the attacker can repeat against any field on any record they can UPDATE. Patches A patch has been introduced that replaces the raw operand in every try operator and in extend with the operand's type name ("string", "int", "array", etc.). - Versions 3.1.0 and later are not affected by this issue. Workarounds Affected users who are unable to update…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
A `LIVE SELECT` subscription records the user's auth state (`$auth`, `$token`, `$session`, `$access`) when it is registered, and the server uses that recorded state to evaluate the table- and row-level `PERMISSIONS` clauses for every subsequent notification. The recorded state is never refreshed. When something changes the user's effective auth state — the originating session is invalidated, the session's TTL expires, or the user signs in, signs up, or authenticates as a different identity on the same connection — the subscription keeps delivering notifications under the old, stale auth state, and the `PERMISSIONS` that should now apply to the connection are never consulted. Impact A user whose session has been revoked, expired, signed out of, or re-authenticated on the same connection continues to receive real-time notifications evaluated against the prior principal. The attacker does not gain access to new resources — only continued access to resources the prior principal was…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
An anonymous caller could degrade `/sql` availability by streaming WebSocket frames many times larger than the operator-configured per-connection limit. The `/sql` upgrade handler accepted anonymous connections and did not propagate `SURREAL_WEBSOCKET_MAX_MESSAGE_SIZE` to the WebSocket protocol layer — incoming bytes accumulated in the per-connection read buffer before `check_anon` could reject the query, so the memory cost was incurred regardless of whether the caller could ever execute SurrealQL. The same upgrade path also silently ignored `--deny-http sql` and `--deny-arbitrary-query *` for authenticated callers, but that secondary effect does not grant new permissions. Impact `SURREAL_WEBSOCKET_MAX_MESSAGE_SIZE` is not applied to anonymous `/sql` connections, so each connection can buffer up to the WebSocket library defaults (16 MiB per frame, 64 MiB per reassembled message) of in-flight bytes regardless of the operator's configured limit. Holding this much memory pinned…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The KILL statement is used to terminate LIVE SELECT subscriptions that capture real-time changes to data within a table. The KILL statement implementation in core/src/expr/statements/kill.rs verifies that the requesting user has database-level access, but does not verify that the requesting user is the owner of the live query being terminated. After passing the validfordb() check, the KILL statement resolves the live query UUID, looks up the corresponding live query entry, and immediately deletes it without comparing the requesting user's identity against the live query owner. This allows any authenticated user with database-level access to terminate any live query in that database, regardless of who created it. The affected user's real-time subscription silently stops receiving updates with no notification that the live query was terminated. The same attack works across privilege levels: a low-privilege record-scoped user can terminate a root user's monitoring live queries. This…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
A `LIVE` query whose `WHERE` clause evaluates to an error caused the source data modifier (the user creating, updating, or deleting a record on the watched table) to fail instead. Calling any arbitrary SurrealQL function with a typed parameter and passing a value of the wrong type — for example `LIVE SELECT * FROM t WHERE string::trim(deny)` — triggered an evaluation error inside the LIVE notification path. That error then propagated through to the triggering write, rolling back the attempted change. While such a `LIVE` query was registered, all `CREATE`, `UPDATE`, and `DELETE` operations on the watched table failed — including those issued by a root user — for as long as the registration remained active. Registering the `LIVE` required `select` permission on the table; no other permission on the table was needed. Impact An authenticated user with `select` permission on a table can prevent all `CREATE`, `UPDATE`, and `DELETE` operations on that table — by any other user, up to…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
An authenticated user could bypass permission rules that gated access on parts of a record's id — most commonly tenant-isolation rules of the form `PERMISSIONS FOR select WHERE id.tenant = $auth.id.tenant`. The same defect also let UNIQUE constraints defined on parts of an id admit duplicate entries. When a query referenced part of a composite record id (`id.tenant`, `id.uid`, …), SurrealDB read the value from the record's editable body fields instead of from the immutable id key. Because the body is editable but the id is fixed at creation, an attacker with write access could set the body field to any value and have permission checks read that spoofed value. Impact What an attacker can do: - Read records hidden by permission rules of the form `id. = $auth. ` (typically tenant- or scope-isolation boundaries) by writing the same-named field on a record they control to the spoofed value. - Cause UNIQUE constraints defined on `id. ` to silently admit duplicate entries, leaving…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
An authenticated record or scope user could read records on any table reachable through a graph edge or REFERENCES TO back-reference, regardless of that table's PERMISSIONS FOR select clause. Traversing SELECT FROM source-edge-target returned full documents from target even when target was defined as PERMISSIONS FOR select NONE. The same bypass extended through multi-hop chains, so any table reachable by a sequence of edges from a readable starting point was exposed. The root cause: GraphEdgeScan and ReferenceScan fetched records straight from storage without routing them through Document::pluckselect, so the target table's permission expression was never consulted. Impact An authenticated record or scope user can read records on any table reachable through a chain of graph edges or back-references from a table they have select on, regardless of the target's PERMISSIONS FOR select clause. Confidentiality-only and bounded to the caller's current database — namespace and database…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
A vulnerability was discovered where the user-supplied WHERE clause in a SELECT statement is evaluated against the full record data before PERMISSIONS FOR SELECT WHERE determines whether the principal is authorised to access that record. A side-effecting expression in the WHERE clause can exfiltrate record contents before the permission check runs. The same ordering bug affects the SET, MERGE, CONTENT and PATCH clauses of update-variant statements (UPDATE, UPSERT-update, INSERT ON DUPLICATE KEY UPDATE, RELATE-update). This vulnerability is confined to the attacker's current database. It does not cross namespace or database isolation boundaries. Impact An authenticated user — including Record and Scope users — can read the full contents of any table in the database they are authenticated against, bypassing PERMISSIONS FOR SELECT WHERE restrictions on those tables. The most direct exfiltration method requires scripting functions to be enabled (--allow-scripting / -A). However,…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The SurrealDB type/kind parser did not enforce the configured recursion depth limit when parsing nested type annotations. The expression parser already enforced the limit for analogous constructs; the kind parser omitted it. An authenticated attacker could send a query with deeply nested type annotations (e.g., `array >>>`) and exhaust server memory, crashing the process. This is an incomplete fix for GHSA-6r8p-hpg7-825g, which addressed the same class of bug in the expression parser but did not cover the kind/type annotation parser code path. Impact An authenticated user with query execution privileges can crash a SurrealDB server with a single WebSocket message containing deeply nested type annotations. Patches A patch has been introduced that wraps `parse_concrete_kind` and the `OPTION ` arm of `parse_inner_kind` with `enter_object_recursion!`, bounding the recursive cycle…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
A single unauthenticated WebSocket message to `/rpc` crashed the SurrealDB server. Sending `use { db: "x" }` without first selecting a namespace hit `.expect("namespace should be set")` in the `use` handler; because `surrealdb-core` is built with `panic = 'abort'`, the panic terminated the process. `use` is callable before `signin`, and the per-method capability check passes by default for guest callers — so no credentials, token, or `--allow-guests` flag are required. Impact An unauthenticated remote attacker who could reach the `/rpc` endpoint could crash the SurrealDB server with a single WebSocket message. No credentials, token, session knowledge, or capability are required. Patches A patch has been introduced that returns a typed `invalid_params` response when `db` is set on a session with no `ns`, replacing the panic. - Versions 3.1.0 and later are not affected by this issue. Workarounds Affected users who are unable to update should restrict network access to the…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The SurrealDB value and JSON parser did not enforce the configured recursion depth limit when parsing nested {, , or ( tokens. The expression parser already enforced the limit for these tokens; the value/JSON parser omitted it. An unauthenticated attacker could send a deeply nested JSON payload to the WebSocket /rpc endpoint and exhaust server memory, crashing the process. This is an incomplete fix for GHSA-6r8p-hpg7-825g, which addressed the same class of bug in the expression parser but did not cover the value/JSON parser code path. Impact An unauthenticated remote attacker can crash a SurrealDB server with a single WebSocket message. No credentials or query execution privileges are required. Patches A patch enforces the configured recursion depth limit in parsevalue and parsejson, bringing them in line with the rest of the parser. - Versions 3.1.0 and later are not affected by this issue. Workarounds Restrict network access to the WebSocket /rpc endpoint to trusted clients.
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The HTTP `/rpc` endpoint has a time-of-check/time-of-use (TOCTOU) race condition on internal session state. When authenticated and unauthenticated requests are processed concurrently, the unauthenticated request can inherit the authenticated user's session and privileges. The `/rpc` endpoint is the primary interface used by all official SurrealDB SDKs. The HTTP `/rpc` handler does not bind each incoming request to an isolated session context. Instead, concurrent requests share mutable authentication state. When an authenticated request sets the session context and an unauthenticated request races in before it is cleared, the unauthenticated request executes with the authenticated user's privileges. The impact depends on the privilege level of the session that is hijacked. If a root or namespace-level user session is inherited, the attacker can read and modify any data, delete records, and create persistent namespace-level users. If a scoped record user session is inherited, the…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The HTTP `/rpc` `sessions` method returned every attached session UUID without authentication, and the `/rpc` handler accepted an arbitrary `session` field with no ownership check. An anonymous caller could enumerate UUIDs and impersonate any authenticated session. "Attached" means sessions registered via `{"method":"attach"}` — the only writer to the HTTP session map. Ordinary stateless `/rpc` requests use ephemeral per-request sessions that are filtered from `sessions()` and destroyed at end-of-request, so they are not enumerable. Exposure - Exposed: clients that issue `attach`, notably the official Rust SDK's `Http`/`Https` engine (auto-attaches once per `Surreal` handle). - Not exposed: REST endpoints (`/sql`, `/key`, `/signin`, `/export`, etc.); WebSocket `/rpc` (per-connection scope, `attach` refused); embedded / MCP usage; ad-hoc `POST /rpc` callers that never `attach`. Impact For each attached and authenticated session, an unauthenticated attacker can…
Recommended action: Upgrade to 3.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
An authenticated user could crash a SurrealDB server with a single query containing a long chain of operators. Such a query — for example `RETURN 1 + 1 + 1 + ...` with tens of thousands of terms — is parsed into an expression tree one level deep per operator. Because the chain is flat and the pratt parser appends to it iteratively, the configured query- and object-recursion limits never fire, so the tree grows unbounded with the length of the query. The root cause: the over-deep tree is later walked recursively, one call per node, when it is dropped, formatted, or lowered for execution — overflowing the thread stack and aborting the process. Impact An authenticated user with query-execution privileges can crash a SurrealDB server with a single query containing a long chain of operators. The whole process aborts, denying service to every namespace and database on that instance until it is restarted. The crash occurs during query processing, before any data is read or written…
Recommended action: Upgrade to 3.1.5 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.