A high-severity misconfiguration in Capgo’s Supabase backend allowed anyone on the internet to retrieve the company’s real-time financial metrics, including monthly recurring revenue, total revenue, and customer counts by plan tier, without logging in or authenticating.
Security researcher riderx disclosed the flaw, tracked as GHSA-73rv-fpp7-r3r4, on March 17. It affects all Capgo versions prior to 12.128.2, with credit for the discovery going to researcher Judel777.
No CVE identifier has been assigned, but GitHub’s advisory database rates the issue as High severity under CWE-200 (Exposure of Sensitive Information) and CWE-284 (Improper Access Control).
Capgo Bug Exposed MRR
Capgo, an over-the-air update platform for Capacitor-based mobile apps, runs its backend on Supabase, a popular Firebase alternative built on PostgreSQL and PostgREST. The vulnerable component was a database table called public.global_stats, which aggregated company-wide operational and financial KPIs.
The problem: Supabase’s Row Level Security (RLS) policies didn’t restrict read access to this table for the anon role. That meant the publicly embedded sb_publishable_* key which ships inside client apps and isn’t considered a secret, was sufficient to query the table directly via PostgREST’s REST interface.
A simple authenticated-free GET request to /rest/v1/global_stats returned structured rows containing:
- Core financial KPIs: mrr and total_revenue
- Revenue broken down by plan tier: solo, maker, team, and enterprise
- Customer counts per plan tier
- Additional telemetry when queried with
select=*, including device/build/update volumes, success rates, and plugin usage breakdowns
In the researcher’s proof-of-concept, a single query returned an MRR figure near 13,717, total revenue of 164,608, and a full customer distribution across tiers, real numbers, live from production, no credentials required.
This isn’t just an embarrassing leak; it’s a textbook example of how Supabase’s security model gets misunderstood. Publishable keys are designed to be public; the actual security boundary is supposed to live in RLS policies.
When teams skip or misconfigure RLS on tables assumed to be “internal,” they inadvertently turn their entire database into a public API.
“The publishable key was never the vulnerability here it did exactly what it’s supposed to do. The real failure was treating a database table like a private admin dashboard when Supabase’s whole architecture assumes RLS is your actual gatekeeper. This is one of the most common and dangerous misconceptions in the current wave of backend-as-a-service adoption.”
For attackers, exposed telemetry like this offers more than bragging rights. Revenue and plan-tier data enable competitor intelligence, while operational metrics device counts, version adoption, success rates can inform reconnaissance for targeted attacks against specific customer segments or software versions still running outdated builds.
Remediation
Capgo patched the issue in version 12.128.2 by revoking anonymous and unnecessary authenticated access to global_stats, per GitHub’s advisory guidance.
The recommended long-term fix mirrors standard Supabase hardening practice: keep sensitive aggregates behind authenticated, admin-only endpoints, or expose only a deliberately redacted subset if public metrics are genuinely needed.
For any team running Supabase in production, this incident is a reminder to audit every table’s RLS policies, not just the ones that “feel” sensitive, but every table reachable through the public API surface.