Skip to main content
Vulnerability Database/CVE-2026-62247

CVE-2026-62247: Supabase Realtime Information Disclosure

CVE-2026-62247 is an information disclosure vulnerability in Supabase Realtime that exposes presence metadata through WebSocket channels. This article covers the technical details, affected versions, and mitigation strategies.

Published:

CVE-2026-62247 Overview

Supabase Realtime contains an authorization flaw that allows private-channel clients to receive presence data they should be denied. The service delivers Broadcast, Presence, and Postgres Changes over WebSockets. Prior to version 2.111.2, Realtime authorization did not correctly honor the per-extension presence.read row-level security (RLS) policy. When a client held presence.write but was explicitly denied presence.read, the server still forwarded presence_diff messages containing other members' metadata. Leaked fields can include application-defined location, online-status, roster, viewing, or typing information. The issue is classified under [CWE-863: Incorrect Authorization] and affects only deployments with differential presence visibility.

Critical Impact

Clients with write-only presence permissions can read other members' presence metadata on private channels, breaking RLS-based access control assumptions.

Affected Products

  • Supabase Realtime versions prior to 2.111.2
  • Deployments using private channels with differential presence.read / presence.write policies
  • Applications relying on per-extension RLS to isolate presence metadata between users

Discovery Timeline

  • 2026-09-21 - CVE-2026-62247 published to NVD
  • 2026-09-22 - Last updated in NVD database

Technical Details for CVE-2026-62247

Vulnerability Analysis

The defect resides in Supabase Realtime's authorization probe logic for presence extensions. Realtime evaluates channel permissions by inserting authorization probe rows and letting Postgres RLS decide the outcome. The pre-patch code inferred read permission from the presence of an inserted row identifier, without independently checking the SELECT policy. This conflated write with read, so a member allowed to insert presence but denied SELECT still passed the read gate. Once the gate opened, the Realtime channel forwarded presence_diff payloads describing joins, leaves, and metadata updates from all other channel members. The postgres_changes extension row data is unaffected, and uniform-visibility deployments carry no differential to exploit.

Root Cause

The probe used RETURNING * on the authorization insert, which forces Postgres to evaluate the SELECT policy for the returned row. Realtime then updated read policies for every extension based on membership in the returned identifier set, effectively treating successful insert as proof of read. Extensions that were never probed were also assigned a boolean read verdict, erasing the distinction between denied and unevaluated.

Attack Vector

An authenticated client connects to a private Realtime channel over WebSocket with credentials that satisfy presence.write but not presence.read. After joining, the client passively receives presence_diff frames broadcast by the server for other members. No additional exploitation primitive is required beyond a valid session and channel subscription.

text
// Patch: lib/realtime/tenants/authorization.ex
     with {:ok, res} <- Repo.all(conn, query, Message) do
       returned_ids = MapSet.new(res, & &1.id)

+      # Only the requested extensions were inserted, so we only set read for those. Extensions that
+      # were not checked are left unevaluated (nil) so callers can tell "denied" (false) apart from
+      # "not checked yet" (nil).
       {:ok,
-       Enum.reduce(@all_extensions, policies, fn extension, acc ->
-         can? =
-           Map.has_key?(messages_by_extension, extension) and
-             MapSet.member?(returned_ids, messages_by_extension[extension])
-
-         Policies.update_policies(acc, extension, :read, can?)
+       Enum.reduce(messages_by_extension, policies, fn {extension, id}, acc ->
+         Policies.update_policies(acc, extension, :read, MapSet.member?(returned_ids, id))
        end)}
     end
   end

Source: Supabase Realtime Commit c039bca

A companion change in lib/realtime/tenants/repo.ex introduces a returning: false option so authorization probe inserts no longer trigger Postgres SELECT policy evaluation, keeping write checks isolated from read checks.

Detection Methods for CVE-2026-62247

Indicators of Compromise

  • WebSocket clients receiving presence_diff events on private channels where their JWT claims should deny presence.read.
  • Realtime tenant logs showing authorization probes that succeed on write but were expected to fail on read for the same extension.
  • Application audit logs recording presence metadata reads from user identities lacking SELECT privileges on presence tables.

Detection Strategies

  • Inventory all Supabase Realtime deployments and compare running versions against 2.111.2 using the container image tag or release manifest.
  • Review RLS policies for any tenant that grants presence.write without a matching presence.read for the same role, flagging channels affected by the differential.
  • Instrument the Realtime tenant to log presence payload delivery per subscriber and correlate against the subscriber's effective RLS verdicts.

Monitoring Recommendations

  • Alert on WebSocket sessions that receive presence broadcasts after authorization decisions denied the read scope for the same channel.
  • Track version drift for the supabase/realtime container in registries and Kubernetes clusters to catch pre-patch instances brought online.
  • Forward Realtime and Postgres audit logs to a central data lake and build queries around presence extension authorization outcomes.

How to Mitigate CVE-2026-62247

Immediate Actions Required

  • Upgrade Supabase Realtime to version 2.111.2 or later across all self-hosted and managed tenants.
  • Audit RLS policies on private channels for any differential between presence.write and presence.read and treat affected channels as exposed until patched.
  • Rotate or invalidate long-lived Realtime JWTs issued to clients that only require write access to presence, in case they were used to read metadata.

Patch Information

The fix ships in Supabase Realtime v2.111.2 via Pull Request #1969 and commit c039bca. Details are documented in the Supabase Security Advisory GHSA-rcr8-2525-4r7p. The patch stops using RETURNING * on authorization probe inserts and only sets read verdicts for extensions actually probed, preserving the distinction between denied and unevaluated.

Workarounds

  • Adopt uniform presence visibility until upgraded — either grant presence.read alongside presence.write or deny both — removing the differential the flaw depends on.
  • Disable the Presence extension on channels where write-only members exist, restricting them to Broadcast until the patch is deployed.
  • Move sensitive presence metadata out of the Presence payload and into a table protected by strict SELECT RLS enforced independently of Realtime.
bash
# Verify the running Supabase Realtime version
docker inspect supabase/realtime --format '{{.Config.Image}}'

# Pull and deploy the patched release
docker pull supabase/realtime:v2.111.2
docker compose up -d realtime

# Confirm the upgrade
curl -s http://localhost:4000/api/health | jq '.version'

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.