Capgo - App ID Confusion via ILIKE Wildcard in Preview Subdomain Lookup
Description
Capgo before 12.128.2 uses ILIKE pattern matching instead of exact matching for app_id lookup in the preview subdomain resolver, allowing underscore characters in app_id to act as SQL wildcards. Attackers can create apps with app_ids differing by one character at underscore positions to cause unintended pattern matches, breaking preview functionality for legitimate apps or causing app-id confusion.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Affected products
1Patches
Vulnerability mechanics
Root cause
"Using PostgreSQL ILIKE pattern matching (instead of exact equality) for app_id lookup in the preview subdomain resolver, where the underscore character is a single-character wildcard."
Attack vector
An attacker creates a second app whose app_id differs from a victim app_id by exactly one character at the underscore position (e.g., `ee.forgr.capacitorXgo.new2` collides with `ee.forgr.capacitor_go.new2`). When the victim's preview domain is requested, the ILIKE query matches both rows, `.single()` fails, and the preview endpoint returns `app_not_found` even though the victim app exists and preview is enabled. The attacker only needs the ability to create apps in the same organization (or any organization where a colliding app_id can be registered) and does not need any special network position beyond normal API access [ref_id=1].
Affected code
The preview subdomain resolver in `supabase/functions/_backend/files/preview.ts` uses `.ilike('app_id', appId)` with `.single()`, and the app_id validation regex in `supabase/functions/_backend/utils/utils.ts` (`reverseDomainRegex = /^[a-z0-9]+(.[\w-]+)+$/i`) permits underscores (`_`). Because `_` is a single-character wildcard in PostgreSQL ILIKE, an app_id containing `_` becomes a pattern rather than a literal match, causing multi-row matches that break `.single()` and return `app_not_found` [ref_id=1].
What the fix does
The advisory recommends replacing `.ilike('app_id', appId)` with `.eq('app_id', appId)` to perform an exact match instead of a pattern match. To preserve case-insensitive lookup, the suggested approach is to store a normalized `app_id_lower` column and compare with `.eq('app_id_lower', appId.toLowerCase())`. Alternatively, escape LIKE wildcards (`_` and `%`) before using ILIKE, or disallow underscores in app_id entirely. The patch in version 12.128.2 implements one of these strategies so that underscores are treated as literal characters, eliminating unintended wildcard collisions [ref_id=1].
Preconditions
- inputThe victim app must have an app_id containing at least one underscore character.
- authThe attacker must be able to create a new app (in the same or a different organization) whose app_id differs from the victim's app_id only at the underscore position(s).
- configThe victim app must have the preview feature enabled in the dashboard.
Reproduction
The advisory provides a full PoC using curl commands against the Capgo API. Steps: (1) identify an existing app with `_` in its app_id (e.g., `ee.forgr.capacitor_go.new2`); (2) create a partner app differing at the underscore position (e.g., `ee.forgr.capacitorXgo.new2`); (3) enable preview for the underscore app; (4) request the preview domain for the underscore app — it returns `app_not_found` (HTTP 400), while the partner app reaches a different gating response (`preview_disabled`). The exact API calls and encoded subdomain format are shown in the advisory [ref_id=1].
Generated on Jun 21, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
2- github.com/Cap-go/capgo/security/advisories/GHSA-cw88-ch2j-8vqjmitrevendor-advisory
- www.vulncheck.com/advisories/capgo-app-id-confusion-via-ilike-wildcard-in-preview-subdomain-lookupmitrethird-party-advisory
News mentions
0No linked articles in our index yet.