npx skills add ...
npx skills add yoanbernabeu/supabase-pentest-skills --skill supabase-audit-realtime
Test Supabase Realtime WebSocket channels for unauthorized subscriptions and data exposure.
npx skills add yoanbernabeu/supabase-pentest-skills --skill supabase-audit-realtime
đ´ CRITICAL: PROGRESSIVE FILE UPDATES REQUIRED
You MUST write to context files AS YOU GO, not just at the end.
- Write to
.sb-pentest-context.jsonIMMEDIATELY after each channel tested- Log to
.sb-pentest-audit.logBEFORE and AFTER each subscription test- DO NOT wait until the skill completes to update files
- If the skill crashes or is interrupted, all prior findings must already be saved
This is not optional. Failure to write progressively is a critical error.
This skill tests Supabase Realtime WebSocket channels for security issues.
Supabase Realtime enables:
| Feature | Description |
|---|---|
| Postgres Changes | Stream database changes |
| Broadcast | Pub/sub messaging |
| Presence | User presence tracking |
Realtime respects RLS policies:
| Test | Purpose |
|---|---|
| Channel enumeration | Find open channels |
| Postgres Changes | Test table streaming |
| Broadcast | Test pub/sub access |
| Presence | Test presence channel access |
Finding: đ´ P0 - User data streaming without authentication! RLS may not be properly configured for Realtime.
Table: orders âââ Subscribe: â Subscribed âââ INSERT events: â Not receiving (RLS working) âââ UPDATE events: â Not receiving (RLS working) âââ DELETE events: â Not receiving (RLS working)
Assessment: â Orders table properly protected.
Table: posts âââ Subscribe: â Subscribed âââ INSERT events: â Receiving published only âââ UPDATE events: â Receiving published only âââ DELETE events: â Receiving published only
Assessment: â Posts streaming respects RLS (published only).
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ Broadcast Channel Test âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
Attempting to subscribe to common channel names...
Channel: room:lobby âââ Subscribe: â Success âââ Messages: Receiving broadcasts âââ Assessment: âšī¸ Open channel (may be intentional)
Channel: admin âââ Subscribe: â Success â Should this be public? âââ Messages: Receiving admin notifications âââ Assessment: đ P1 - Admin channel publicly accessible
Channel: notifications âââ Subscribe: â Success âââ Messages: Receiving user notifications for ALL users! âââ Assessment: đ´ P0 - User notifications exposed
Sample Notification:
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ Presence Test âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
Channel: online-users âââ Subscribe: â Success âââ Presence List: Receiving all online users âââ Users Online: 47
Sample Presence Data:
Assessment: đ P1 - User presence data exposed Consider if email/user_id should be visible.
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ Summary âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
Postgres Changes: âââ đ´ P0: users table streaming all data âââ â PASS: orders table protected by RLS âââ â PASS: posts table correctly filtered
Broadcast: âââ đ´ P0: notifications channel exposing user data âââ đ P1: admin channel publicly accessible âââ âšī¸ INFO: lobby channel open (review if intended)
Presence: âââ đ P1: online-users exposing user details
Critical Findings: 2 High Findings: 2
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ Recommendations âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
FIX USERS TABLE RLS Ensure RLS applies to Realtime:
SECURE BROADCAST CHANNELS Use Realtime Authorization:
LIMIT PRESENCE DATA Only share necessary information:
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
| Issue | Cause | Fix |
|---|---|---|
| All data streaming | RLS not enabled/configured | Enable and configure RLS |
| Broadcast open | No channel authorization | Add channel policies |
| Presence exposed | Too much data tracked | Minimize tracked data |
â ī¸ This skill MUST update tracking files PROGRESSIVELY during execution, NOT just at the end.
DO NOT batch all writes at the end. Instead:
.sb-pentest-audit.log.sb-pentest-context.jsonThis ensures that if the skill is interrupted, crashes, or times out, all findings up to that point are preserved.
Update .sb-pentest-context.json with results:
Log to .sb-pentest-audit.log:
If files don't exist, create them before writing.
FAILURE TO UPDATE CONTEXT FILES IS NOT ACCEPTABLE.
đ Evidence Directory: .sb-pentest-evidence/06-realtime-audit/
| File | Content |
|---|---|
websocket-connection.json | WebSocket connection test |
postgres-changes/[table].json | Table subscription results |
broadcast-channels/[channel].json | Broadcast channel access |
presence-data/[channel].json | Presence data exposure |
supabase-audit-rls â RLS affects Realtimesupabase-audit-tables-read â API access is relatedsupabase-report â Include in final report-- Realtime authorization (Supabase extension)
-- Add policies to realtime.channels virtual table
-- Only authenticated users can join
CREATE POLICY "Authenticated users join channels"
ON realtime.channels FOR SELECT
USING (auth.role() = 'authenticated');
-- Or restrict specific channels
CREATE POLICY "Admin channel for admins"
ON realtime.channels FOR SELECT
USING (
name != 'admin' OR
(SELECT is_admin FROM profiles WHERE id = auth.uid())
);{
"realtime_audit": {
"timestamp": "2025-01-31T14:00:00Z",
"connection": "established",
"postgres_changes": {
"users": {
"subscribed": true,
"receiving_events": true,
"severity": "P0",
"finding": "All user data streaming without RLS"
},
"orders": {
"subscribed": true,
"receiving_events": false,
"severity": null,
"finding": "Properly protected by RLS"
}
},
"broadcast": {
"notifications": {
"accessible": true,
"severity": "P0",
"finding": "User notifications exposed"
},
"admin": {
"accessible": true,
"severity": "P1",
"finding": "Admin channel publicly accessible"
}
},
"presence": {
"online-users": {
"accessible": true,
"severity": "P1",
"users_visible": 47,
"finding": "User presence data exposed"
}
}
}
}-- Ensure RLS is enabled
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- Policy for authenticated users only
CREATE POLICY "Users see own profile" ON users
FOR SELECT
USING (auth.uid() = id);
-- Realtime will now only stream changes for the authenticated user's row// Client: Check access before subscribing
const { data: canAccess } = await supabase
.from('channel_access')
.select('*')
.eq('channel', 'admin')
.eq('user_id', userId)
.single();
if (canAccess) {
const channel = supabase.channel('admin');
channel.subscribe();
}// Before (too much data)
channel.track({
user_id: userId,
email: email,
name: fullName,
avatar: avatarUrl
});
// After (minimal data)
channel.track({
online_at: new Date().toISOString()
// User details fetched separately if needed
});