{
  "affected": [
    {
      "database_specific": {
        "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-h4h3-3rfj-x6fq/GHSA-h4h3-3rfj-x6fq.json"
      },
      "package": {
        "ecosystem": "crates.io",
        "name": "surrealdb",
        "purl": "pkg:cargo/surrealdb"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0"
            },
            {
              "fixed": "3.1.5"
            }
          ],
          "type": "SEMVER"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-63309"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-200"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-19T22:10:50Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "A field can be hidden from a user with a field-level SELECT permission (`DEFINE FIELD code ON secret PERMISSIONS FOR select WHERE owner = $auth.id`). When that field is indexed, a record user who cannot read it could still recover the relative ordering of its values across every record by issuing `ORDER BY <field>`: the field came back `null` as intended, but the rows were returned in the hidden values' true sorted order.\n\nTo satisfy the sort, the planner selects the field's index and walks it in value order; the field-level permission is applied later, when the row is projected, so the value is nulled but the row order already encodes it. The guard that withholds restricted fields from the `WHERE` path was never applied to `ORDER BY`.\n\n## Impact\n\nWhat an attacker **can** do:\n\n- As a record (scope) user with table SELECT, learn the relative ordering of a field hidden by a field-level SELECT permission, across other users' records, by ordering on it when an index covers the field — the value returns `null`, but the rows come back in the hidden values' order.\n- With rows they control in the same table, use that ordering to narrow the hidden values toward exact ones.\n\nWhat it **can't** do:\n\n- Read the field value directly — only its relative ordering leaks; the projected value is correctly redacted.\n- Cross table, record, or namespace/database boundaries — the table's SELECT permission and any row-level `WHERE` are still enforced, so only records the caller may already read are ordered.\n- Leak anything when the restricted field is not indexed, affect root or record-owner sessions, or modify data (confidentiality only).\n\n## Patches\n\nThe query planner now applies the field-permission guard to the `ORDER BY` clause as well as the `WHERE` clause. When an ordered field is hidden from the caller by a field-level SELECT permission, the index sort pushdown is withheld and the rows are sorted after redaction instead, so the row order no longer reflects the hidden values. The dynamic-scan fallback is closed the same way, and a regression test was added.\n\nThe fix is included in SurrealDB 3.1.5.\n\n## Workarounds\n\nUsers unable to upgrade are advised to consider the following:\n\n- Force the legacy executor with `SURREAL_PLANNER_STRATEGY=compute-only`; the sort then runs after redaction, so no ordering leaks.\n- Do not place an index on a field whose values are hidden by a field-level SELECT permission — without the index the leak does not occur.\n- Do not rely on field-level SELECT permissions to hide values on indexed fields from record users; restrict at the table level instead.\n- Use namespace / database isolation as the primary trust boundary where feasible.\n\n## References\n\n- [SurrealQL Documentation — DEFINE FIELD](https://surrealdb.com/docs/surrealql/statements/define/field)\n- [SurrealQL Documentation — DEFINE INDEX](https://surrealdb.com/docs/surrealql/statements/define/indexes)\n- [SurrealQL Documentation — DEFINE TABLE … PERMISSIONS](https://surrealdb.com/docs/surrealql/statements/define/table)\n- Related advisory (same class, indexed COUNT variant): [GHSA-c8jx-96c9-8xrp](https://github.com/surrealdb/surrealdb/security/advisories/GHSA-c8jx-96c9-8xrp)\n- `fix(planner): prevent ORDER BY value-ordering oracle on restricted SELECT fields`\n- `fix(planner): close ORDER BY value-ordering oracle on the DynamicScan fallback`\n\n## Acknowledgements\n\nThanks to George Chen ([@geo-chen](https://github.com/geo-chen)) for finding and reporting this issue.",
  "id": "GHSA-h4h3-3rfj-x6fq",
  "modified": "2026-11-04T02:56:06.067940291Z",
  "published": "2026-06-19T22:10:50Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/surrealdb/surrealdb/security/advisories/GHSA-h4h3-3rfj-x6fq"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/surrealdb/surrealdb"
    }
  ],
  "schema_version": "1.9.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "SurrealDB: Indexed ORDER BY leaks the value ordering of a SELECT-restricted field"
}