Capgo - Unauthenticated API Key Validity Oracle and User Identity Disclosure via get_identity_apikey_only RPC
Description
Capgo before 12.128.2 contains an unauthenticated security definer RPC function get_identity_apikey_only that returns the owning user_id for supplied API keys, creating an API key validity oracle and user identity disclosure primitive. Attackers can call this endpoint with valid or invalid API keys to confirm key validity and map keys to user identifiers, then chain results into other exposed RPCs like get_orgs_v6 to retrieve organization membership and management email PII.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Affected products
2Patches
Vulnerability mechanics
Root cause
"The SECURITY DEFINER RPC function `get_identity_apikey_only` is granted to the unauthenticated `anon` role, allowing anyone to probe API key validity and retrieve the owning `user_id`, which can then be chained into other exposed RPCs to leak PII."
Attack vector
An unauthenticated attacker can call `get_identity_apikey_only` using the public anon API key (`sb_publishable_*`) by sending a POST request to the Supabase REST endpoint with a `capgkey` header. A valid key returns the owning `user_id` (UUID), while an invalid key returns `null`, creating an API key validity oracle [ref_id=1]. The attacker can then chain the leaked `user_id` into the similarly exposed `get_orgs_v6(userid)` RPC to retrieve organization membership details and the `management_email` (PII) [ref_id=1]. No authentication is required beyond the public anon key.
Affected code
The vulnerability resides in the Supabase RPC function `public.get_identity_apikey_only(keymode[])`, defined in `supabase/migrations/20250530233128_base.sql`. The function is declared `SECURITY DEFINER` and explicitly granted to the `anon` role via `GRANT ALL ON FUNCTION ... TO "anon"`. Additionally, broad default privileges (`ALTER DEFAULT PRIVILEGES ... GRANT ALL ON FUNCTIONS TO "anon"`) increase exposure. The chained endpoint `get_orgs_v6(userid)` is also callable by anon and returns `management_email` (PII) without authorization checks.
What the fix does
The advisory recommends revoking anon access to `get_identity_apikey_only` via `REVOKE ALL ON FUNCTION public.get_identity_apikey_only(...) FROM anon;` and similarly reviewing/revoking anon access for related identity helpers (`get_identity_org_allowed`, `get_identity_org_appid`, `get_identity(keymode[])`) [ref_id=1]. It also advises removing the broad `GRANT ALL ON FUNCTIONS/TABLES TO anon` default privileges in favor of explicit grants, and ensuring `get_orgs_v6(userid)` enforces authorization (e.g., `auth.uid() = userid`) and stops returning `management_email` to unauthorized callers [ref_id=1]. The patched version is 12.128.2.
Preconditions
- networkAttacker must have network access to the Supabase REST endpoint and possess the public anon API key (sb_publishable_*), which is typically embedded in client-side applications and considered public.
- authNo authentication required; the anon key is publicly available and the RPC is explicitly granted to the 'anon' role.
- inputAttacker must supply a capgkey value (valid or invalid) to probe the oracle.
Generated on Jun 22, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
2News mentions
0No linked articles in our index yet.