CVE-2026-88861
Executive Summary
CVE-2026-88861 is an authentication bypass vulnerability in Capgo (Cap-go/capgo.app), an open-source over-the-air (OTA) update platform for Capacitor-based mobile applications. The flaw allows an attacker who knows only a victim's password to obtain a privileged session and mint a persistent, app-scoped app_admin API key — even when the victim's account has a verified MFA factor — because the Edge authorization path validates the user's identity but never validates the session's assurance level (aal). This defeats MFA's protective intent, thereby enabling privileged operations such as modification of production OTA channel configurations. The vulnerability affects all versions and remains unpatched at the time of publication.
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
Technical Analysis
The vulnerability resides in the Supabase Edge function authorization path of Capgo. Supabase Auth models session assurance using the Authentication Assurance Level (AAL) framework:
- aal1: a session authenticated with a single factor (e.g., password only).
- aal2: a session authenticated with two or more factors (e.g., password plus TOTP).
The intended security posture is that operations requiring strong authentication must demand aal2 and reject aal1 sessions when the account has a verified MFA factor enrolled. In Capgo's implementation, two code paths deviate from this intent:
JWT middleware (
foundJWT()insupabase/functions/_backend/utils/hono_middleware.ts) — This middleware, built on the Hono web framework, accepts and processes incoming JWTs without validating theaalclaim. It establishes that the bearer is a signed-in user, but does not distinguish between a single-factor (aal1) and a multi-factor (aal2) session.Direct RBAC path (
checkPermission()/checkPermissionPg()insupabase/functions/_backend/utils/rbac.ts) — These functions call the database-side routinepublic.rbac_check_permission_direct(). The RBAC check authorizes actions purely by user ID, without receiving or evaluating the session's assurance level. As a result, when an account has a verified MFA factor but the current session is only aal1, the RBAC layer still grants the account's full privileges.
By contrast, the description notes that Capgo's public.verify_mfa() control correctly requires aal2. This inconsistency — one control enforcing MFA assurance, the authorization path not enforcing it — is the crux of CWE-288 (Authentication Bypass Using an Alternate Path or Channel). The MFA requirement is enforced on some code paths but not on the primary authorization path, allowing an attacker to reach privileged functionality through the alternate path.
Because the direct RBAC check authorizes by user ID, and the JWT middleware accepts the aal1 token as proof of that identity, the attacker need only possess the victim's password to assume the victim's RBAC identity. This is a classic "MFA bypass through inconsistent enforcement" pattern.
Exploitation Scenarios
No public PoC is available; the following attack chain is inferred from the vulnerability class and the NVD description. Only components named in the description are referenced.
Reconnaissance / target identification. The attacker identifies a Capgo deployment (a Cap-go/capgo.app instance) and a target user account with privileged RBAC permissions (e.g., an administrator or a user with
app_admin). The attacker does not need a session token, MFA code, or device access — only knowledge of the victim's password, consistent with CVSS PR:L (privileges required: Low) and AC:L (attack complexity: Low).Triggering the bypass. The attacker authenticates as the victim using the password alone. Supabase Auth issues a session whose assurance level is
aal1(single factor). Although the account has a verified MFA factor, the attacker never satisfies it. The attacker presents this aal1 JWT to the Capgo Edge functions.foundJWT()insupabase/functions/_backend/utils/hono_middleware.tsaccepts the token without validating its assurance level, andcheckPermission()/checkPermissionPg()insupabase/functions/_backend/utils/rbac.ts— which callpublic.rbac_check_permission_direct()— authorize requests by user ID without checking the sessionaal. The MFA control enforced elsewhere viapublic.verify_mfa()is never invoked on this path.Execution / payload method. The vulnerability-class step is simply a privileged API call made with the aal1 JWT. Because the RBAC layer grants the victim's privileges, the attacker can invoke privileged functionality. Per the NVD description, the attacker mints a persistent, app-scoped
app_adminAPI key. This key is not bound to the aal1 session's lifetime.Post-exploitation impact. The minted
app_adminAPI key remains valid even after the aal1 session is logged out, providing durable privileged access. The description confirms the impact by a validated operation: changing a public production OTA channel from bundle1.0.0to1.0.1. More broadly, an attacker withapp_admincan modify production OTA channel configurations, which in a Capgo deployment governs which over-the-air bundle is served to — and installed by — mobile app clients. Malicious channel manipulation enables pushing attacker-controlled content to production mobile clients, a severe downstream impact (CVSS I:H). Note: the persistent API key is the durable artifact; defenders should treat its issuance via an aal1 session as the primary anomaly.
Impact Assessment
The CVSS 3.1 base score is 8.3 (High) with vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L:
- AV:N — Reachable over the network; the Edge functions are network-exposed.
- AC:L — No compounding conditions; the attacker only needs a valid password.
- PR:L — Requires the victim's credentials (password), i.e., low privileges.
- UI:N — No victim interaction is required.
- S:U — Impact confined to Capgo's authorization scope.
- C:H — Attacker gains access to privileged account resources/data.
- I:H — Attacker can alter production OTA channel configurations and mint admin keys.
- A:L — Limited availability impact.
Business impact centers on the integrity of the mobile software distribution pipeline. An attacker who can alter OTA channel configurations can influence what code or bundles are delivered to production mobile users, compromising the trust chain of Capacitor app deployments. Because MFA is defeated, organizations relying on MFA as their primary account-takeover defense lose that control for Capgo administrative accounts. Blast radius includes any app served by the affected Capgo instance and all end users of that app. The persistence of the minted app_admin key means remediation of the session alone is insufficient; keys must be revoked and rotated.
Detection Guidance
Sigma Rule
Detects Cap-go/Capgo Edge function authentication events where a privileged RBAC authorization or admin key mint occurs on an aal1 session.
title: Capgo MFA Bypass - Privileged RBAC on aal1 Session (CVE-2026-88861)
id: 0f3a9e2c-7b21-4f5d-9c1a-8e6b0d2f4a11
status: experimental
description: Detects privileged Capgo Edge RBAC authorization or app_admin key mint from an aal1 (single-factor) session that should require aal2.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-88861
author: Valters IT Threat Intelligence
date: 2026/01/01
tags:
- attack.persistence
- attack.t1078
logsource:
product: capgo
service: edge
detection:
selection:
event.action:
- 'rbac_check_permission_direct'
- 'app_admin_key_minted'
- 'channel_config_update'
filter_aal1:
session.aal: 'aal1'
filter_mfa_present:
user.mfa_verified: true
condition: selection and filter_aal1 and filter_mfa_present
falsepositives:
- Legitimate aal1 sessions on accounts without MFA (excluded by filter_mfa_present)
level: high
YARA Rule
YARA operates on files; this is a source-level indicator for Capgo deployments. The rule matches the vulnerable code pattern without requiring a specific patch string.
rule CVE_2026_88861_Capgo_MFA_Bypass
{
meta:
author = "Valters IT Threat Intelligence"
description = "Detects Capgo Edge authorization code lacking AAL validation (CVE-2026-88861)"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-88861"
date = "2026-01-01"
severity = "high"
strings:
$f1 = "foundJWT" ascii
$f2 = "hono_middleware" ascii
$f3 = "checkPermission" ascii
$f4 = "checkPermissionPg" ascii
$f5 = "rbac_check_permission_direct" ascii
$f6 = "verify_mfa" ascii
$mfa1 = "aal2" ascii
$mfa2 = "aal1" ascii
condition:
filesize < 2MB and
(
($f1 and $f2 and not $mfa1) or
(($f3 or $f4) and $f5 and not $mfa1)
)
}
Suricata IDS Rule
Monitors Capgo/Supabase Edge HTTP traffic for privileged RBAC or channel-modification requests and flagging those lacking an MFA step-up. Adjust ports/regex to the deployment's actual Edge endpoint.
alert http any any -> any any (msg:"CVE-2026-88861 Capgo Privileged Channel Config Change (possible MFA bypass)"; flow:established,to_server; http.method; content:"PATCH"; http.uri; content:"channel"; nocase; http.uri; content:"config"; nocase; http.header; content:"Authorization"; nocase; http.header; content:"Bearer"; nocase; classtype:attempted-admin; reference:cve,2026-88861; reference:url,nvd.nist.gov/vuln/detail/CVE-2026-88861; sid:202688861; rev:1;)
Elastic Detection
EQL targeting Capgo Edge authorization logs. Flags a privileged RBAC decision or admin-key mint tied to aal1 while the account has a verified MFA factor.
sequence by user.id with maxspan=5m
[ authentication where event.outcome == "success" and session.assurance_level == "aal1" ]
[ authorization where event.action in ("rbac_check_permission_direct", "app_admin_key_minted", "channel_config_update")
and event.outcome == "success" ]
Splunk SPL Query
index=capgo sourcetype=capgo:edge
(event=rbac_check_permission_direct OR event=app_admin_key_minted OR event=channel_config_update)
session_aal=aal1 user_mfa_verified=true
| stats count min(_time) as first_seen max(_time) as last_seen values(event) as actions by user_id src_ip
| where count > 0
| convert ctime(first_seen) ctime(last_seen)
| sort - count
Wazuh OSSEC Rule
<group name="capgo,authentication_bypass,CVE-2026-88861,">
<rule id="20268861" level="12">
<decoded_as>json</decoded_as>
<field name="event.action">rbac_check_permission_direct|app_admin_key_minted|channel_config_update</field>
<field name="session.aal">aal1</field>
<description>CVE-2026-88861: Privileged Capgo RBAC action on aal1 session - possible MFA bypass</description>
<mitre>
<id>T1078</id>
</mitre>
<group>authentication_bypass,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence: 0/4 (UNPATCHED — no patch evidence from any tracked source). No vendor fix, workaround, or affected-version patch data is currently available. public.verify_mfa() already enforces aal2, demonstrating the correct pattern — the fix must propagate that enforcement to foundJWT() and the direct RBAC path.
Immediate mitigations.
- Disable or de-enroll MFA-dependent assumptions for privileged Capgo accounts and treat password compromise as equivalent to full compromise until a patch exists; enforce strong, unique passwords and rotate them if any suspicion of compromise exists.
- Revoke and rotate all app-scoped
app_adminAPI keys; the description confirms such keys survive aal1 session logout, so key revocation is required, not just session termination. - Restrict network access to Capgo Edge endpoints via IP allow-listing or a WAF, limiting where an attacker can reach the vulnerable path.
- Monitor and alert on any production OTA channel configuration changes (e.g., bundle version changes such as 1.0.0 to 1.0.1) out of band.
Patch/upgrade steps.
- No patch exists. Monitor the Cap-go/capgo.app repository and vendor channels for a release that validates the JWT
aalclaim infoundJWT()and passes/checks session assurance throughcheckPermission()/checkPermissionPg()/public.rbac_check_permission_direct(). When published, upgrade via the project's standard deployment process and re-validate MFA enforcement end to end.
- No patch exists. Monitor the Cap-go/capgo.app repository and vendor channels for a release that validates the JWT
Long-term hardening.
- Adopt defense-in-depth: enforce authorization decisions at a single choke point that always evaluates session assurance, rather than relying on the JWT middleware alone.
- Require step-up to aal2 for all privileged actions and for API-key issuance; treat key minting as a security-sensitive operation requiring fresh strong authentication.
- Bind API keys to the assurance level and MFA freshness of the session that created them, and expire them aggressively.
- Add continuous regression testing for MFA bypass across all authorization code paths, including the direct RBAC database routine.
References
- NVD — CVE-2026-88861: https://nvd.nist.gov/vuln/detail/CVE-2026-88861
- Capgo (Cap-go/capgo.app) project repository: https://github.com/Cap-go/capgo.app
- CWE-288 — Authentication Bypass Using an Alternate Path or Channel: https://cwe.mitre.org/data/definitions/288.html
- Supabase Auth — Authentication Assurance Levels (AAL) / MFA documentation: https://supabase.com/docs/guides/auth/auth-mfa
- MITRE ATT&CK T1078 — Valid Accounts: https://attack.mitre.org/techniques/T1078/
Evidence note: No public PoC, no exploit code, no Nuclei template, and no CISA KEV entry exist for this CVE at time of publication. No threat-actor campaign attribution available. EPSS has not yet scored this CVE by FIRST.org; no EPSS value is reported.