Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Realtime RLS API Call not Respecting private: true flag #1274

Open
2 tasks done
kaceycleveland opened this issue Sep 21, 2024 · 1 comment
Open
2 tasks done

Realtime RLS API Call not Respecting private: true flag #1274

kaceycleveland opened this issue Sep 21, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@kaceycleveland
Copy link

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

There is more context here in this discord thread:
https://discord.com/channels/839993398554656828/1287055628769951754/1287055628769951754

To summarize though, when using supabase-js and following the docs for authorized real time broadcasts, only certain methods respect the { config: { private: true } } flag. More specifically, the REST endpoint for prompting a broadcast as described here does not respect it:
https://supabase.com/docs/guides/realtime/broadcast?queryGroups=language&language=js#send-messages-using-rest-calls

A clear and concise description of what the bug is.

To Reproduce

Join a channel as a client with a given RLS policy that only allows for authenticated listeners:

    const channelName = `project_${project.id}`;
    const channel = supabase.channel(channelName, {
      config: { private: true, broadcast: { self: true } },
    });
    
      channel.on("broadcast", { event: "test" }, (payload) =>
      console.log("payload", payload),
    );

    channel.subscribe((status, err) => {
      if (status === "SUBSCRIBED") {
        console.log("Connected!", status);
      } else {
        console.log("realtime error", status);
      }
    });

RLS on realtime.messages:

alter policy "Allow listening for broadcasts for authenticated users only"
on "realtime"."messages"
to authenticated
using (
  (extension = 'broadcast'::text)
);

Trigger a message from a separate machine (in this case, I have a lambda function triggering it using the service key):

      const channelName = `project_${project.data.id}`;
      const channel = supabaseAdmin.channel(channelName, {
        config: { private: true },
      });
      
      channel.send({
      type: 'broadcast',
      event: 'test',
      payload: { message: 'Hi' },
     })

The channel.send function triggers a broadcast on a public channel when I expect it to trigger on a private channel given private: true. This was confirmed to be an issue because the send command has conditional logic based on being connected to the socket. Therefore, the workaround I provided below works because it waits until the subscription is connected first before sending.

Expected behavior

channel.send should send on a private channel instead of a public channel when private: true is set.

Screenshots

If applicable, add screenshots to help explain your problem.

System information

  • OS: Windows WSL
  • Browser (if applies) chrome
  • Version of supabase-js: 2.45.4
  • Version of Node.js: 22.8.0

Additional context

I have a work around that awaits the subscription to the channel before sending.

      const subscribedResult = await new Promise((resolve, reject) => {
        channel.subscribe(async (status, err) => {
          console.log("subscribing...");
          if (status === "SUBSCRIBED") {
            await channel.send({
              type: "broadcast",
              event: "test",
              payload: { message: "Hi" },
            });
            resolve("success");
          } else {
            console.log("realtime error", status);
            reject(err);
          }
        });
      });
@kaceycleveland kaceycleveland added the bug Something isn't working label Sep 21, 2024
@daveycodez
Copy link

daveycodez commented Nov 5, 2024

With private set to false, any stranger can use your Anon key to create channels. There is a message cap of 500 messages per second for Pro accounts. That means that any bot can send 500 messages per second.

There's 2,628,288 seconds in 30 days.

So that's 1,314,144,000 messages that can be sent. 1.3 billion messages can be spammed per month to any Supabase project with just an Anon key and minimal coding knowledge.

Pricing for Pro plan ->
5 Million included
then $2.50 per Million

1309144000 messages in overages per month. Divided by 1 million and multiplied by $2.50 you get $3,272.86 in cost that could be easily imposed on any Pro tier Supabase project just by this existing. This is a huge security hole.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants