VYPR
Unrated severityNVD Advisory· Published Jun 22, 2026

Cap-go - Privilege Inversion in Build Log Stream via SSE Disconnect

CVE-2026-56280

Description

Cap-go before 12.128.2 contains a privilege inversion vulnerability in GET /build/logs/:jobId that allows read-only API key holders to cancel running native builds. The endpoint registers an abort listener on the SSE stream that unconditionally invokes cancelBuildOnDisconnect() using the privileged server-side BUILDER_API_KEY when clients disconnect, bypassing the app.build_native permission check required by the explicit POST /build/cancel/:jobId endpoint. Attackers with read-only API keys can repeatedly disrupt native build operations and CI/CD workflows by opening the log stream and dropping the connection.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Affected products

1

Patches

Vulnerability mechanics

Root cause

"The SSE disconnect handler in /build/logs/:jobId registers an abort listener that unconditionally cancels the build using the privileged server-side BUILDER_API_KEY, bypassing the app.build_native permission check required by the explicit cancel endpoint."

Attack vector

An attacker holding a read-only API key (e.g., `org_member`, `app_reader`, or `app_uploader` roles) can cancel any running native build for the target app by opening the SSE log stream at `GET /build/logs/:jobId` and then dropping the TCP connection [ref_id=1]. The server unconditionally fires `POST /jobs/:jobId/cancel` via `cancelBuildOnDisconnect()` using its privileged `BUILDER_API_KEY`, bypassing the `app.build_native` permission check enforced on the explicit cancel endpoint [ref_id=1]. This allows repeated disruption of native build operations and CI/CD workflows with no audit trail linking the action to the read-only principal [ref_id=1].

Affected code

The vulnerability resides in `supabase/functions/_backend/public/build/logs.ts` lines 164–166, where an abort listener is registered unconditionally on the SSE stream. When a client disconnects, `cancelBuildOnDisconnect()` is invoked using the privileged server-side `BUILDER_API_KEY` without re-checking permissions. The route `GET /build/logs/:jobId` in `supabase/functions/_backend/public/build/index.ts` line 50 only requires `app.read_logs` (read-only), while the explicit cancel endpoint `POST /build/cancel/:jobId` at line 61 correctly requires `app.build_native` (write).

What the fix does

The advisory recommends either removing the disconnect-triggered cancellation entirely from `/build/logs/:jobId` or gating the abort handler with a permission check before registering it [ref_id=1]. Specifically, the abort listener in `logs.ts` line 162 should be guarded by `checkPermission(c, 'app.build_native', { appId: buildRequest.app_id })` so that only principals with write-level permission can trigger cancellation on disconnect [ref_id=1]. This ensures all cancel paths—including indirect server-side triggers—enforce the same authorization boundary as the explicit cancel endpoint.

Preconditions

  • authAttacker must hold a valid read-only API key scoped to the target app (e.g., org_member, app_reader, or app_uploader role)
  • configA native build must be actively running for the target app
  • networkAttacker must be able to open an SSE connection to GET /build/logs/:jobId and then drop the TCP connection

Generated on Jun 23, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.