All vulnerabilities
GHSA-2jc3-58q7-mm2j

surrealdb: The `revoke` RPC invalidates any user's refresh token without authentication or proof of possession

surrealdb
CVSS
6.5Medium
ExploitationNo known exploitationNot in CISA KEV, which does not prove it is unexploitedCISA KEV
Exploit odds (EPSS)No scoreNo FIRST EPSS score in this snapshot yet
Fixed in3.3.0Fixed versionGitHub
Published28 Sep 2026Updated 28 Sep 2026GitHub

What fixes it

A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.

Description

SurrealDB record access methods defined WITH REFRESH issue a refresh token that a client can later exchange for new access tokens. The revoke RPC method invalidates such a refresh token. That method performed no authentication and no proof of possession: it took the target namespace, database, and access method from an access token that was decoded without verifying its signature, took the grant identifier from a refresh string that was only format-checked, and then carried out the revocation as root. It never verified that the caller actually held the refresh token's key.

A grant identifier is not a secret. ACCESS <ac> SHOW ALL reveals every grant's id (only the key is redacted) and requires only VIEWER-level view permission on the access method, and the identifier is embedded in every issued refresh token. So any caller who learned a grant identifier — a low-privileged database user, or anyone to whom a token leaked — could permanently revoke the corresponding refresh token without holding its key. This turned an operation that over SurrealQL (ACCESS ... REVOKE GRANT) requires the Owner role into one reachable by a low-privileged, or in principle unauthenticated, RPC caller.

The victim's refresh token was then permanently invalidated: every subsequent refresh failed, forcing re-authentication.

Impact

This affects deployments that use record access methods defined WITH REFRESH and expose the /rpc endpoint (the default), where an attacker can learn a grant identifier — for example through any database-level account (including VIEWER) via ACCESS <ac> SHOW ALL, or through a leaked refresh token.

What an attacker can do:

  • Permanently revoke another user's refresh token by supplying its grant identifier to the revoke RPC, without holding the token's key.
  • Enumerate all grant identifiers for an access method with only VIEWER-level view permission, and revoke every user's refresh token for that method, denying refresh to all of its users.

What it can't do:

  • Recover the refresh token's key, sign in as the victim, or read the victim's data — this is not account takeover or data disclosure. The victim can re-authenticate with their credentials.
  • Guess a grant identifier without a disclosure channel; the identifier carries roughly 68 bits of entropy, so a low-privilege or token-leak channel is required in practice.
  • Affect deployments that do not use WITH REFRESH.

Patches

Revoking a refresh token now requires proof of possession. The presented refresh key is verified with a constant-time comparison against the stored grant — the same check the refresh (sign-in) path already performs — before anything is revoked, so only the holder of the token (or an Owner acting through SurrealQL) can revoke it. Every failure is reported as an opaque authentication error, so a caller cannot distinguish a wrong key from a missing, expired, or already-revoked grant.

  • Versions 3.3.0 and later are not affected by this issue.

Workarounds

Users unable to patch should consider the following workarounds:

  • Deny the revoke RPC method via capabilities where refresh-token revocation is not required (for example --deny-rpc revoke, env SURREAL_CAPS_DENY_RPC).
  • Restrict network access to the /rpc endpoint to trusted clients.
  • Treat grant identifiers as sensitive: limit who holds database-level accounts that can run ACCESS <ac> SHOW ALL, since it discloses grant identifiers.

References

Acknowledgements

Thank you to Yanhaoxi for reporting this issue.

Text from GitHub Advisory Database

Affected versions 1

  • surrealdb, rust>= 3.0.0, < 3.3.0GitHub