CVE-2026-91147: Cockpit: cockpit: denial of service in `cockpit-ws` due to url-root handling without a trailing slash
A flaw was found in cockpit-ws. This vulnerability allows a remote, unauthenticated attacker to cause a Denial of Service (DoS) by sending a specially crafted request. When the WebService.UrlRoot is configured and a request is made to the exact URL-root prefix without a trailing slash, cockpit-ws can terminate unexpectedly. This issue leads to the unavailability of the Cockpit web service.
Other sources
AIONLYREPORT package: cockpit-356-1.el10 ------ Summary: Reachable Assertion DoS in cockpit-ws when WebService.UrlRoot is set and requested without trailing slash: an unauthenticated request to the exact configured URL-root prefix can yield an empty internal path and trigger a reachable gassert(), aborting cockpit-ws. Requirements to exploit: The target must run cockpit-356-1.el10 with a non-empty [WebService] UrlRoot, and the attacker must be able to send an exact-prefix request without a trailing slash through a route that does not normalize or redirect it first. No authentication or user interaction is required. The availability impact depends on a build where gassert() is active. Component affected: cockpit-356-1.el10, specifically src/ws/cockpitwebserver.c in pathhasprefix(), cockpitwebrequestprocess(), and cockpitwebserverdefaulthandlestream(). Version affected: cockpit-356-1.el10 when [WebService] UrlRoot is configured to a non-empty prefix Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Notified via this report. CVSS: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H - 5.9 (MEDIUM) AV:N - The issue is triggered by a network request to the Cockpit web service. AC:H - Exploitation requires a non-default but documented UrlRoot deployment, the exact configured prefix to be requested without a trailing slash, and a request path that is not normalized away before cockpit-ws processes it. The trigger also depends on an assertion-enabled build. PR:N - No authentication is required. UI:N - No user interaction is required. S:U - The impact is confined to the Cockpit web service process. C:N - No confidentiality impact is established. I:N - No integrity impact is established. A:H - A successful trigger reaches a gassert() and aborts cockpit-ws, interrupting service availability. Impact: Moderate. Assuming the shipped build retains gassert(), this is a remote unauthenticated availability issue. Under Red Hat's guidance, remote DoS would normally lean Important, but this case depends on a non-default yet documented UrlRoot deployment and on the exact prefix request reaching cockpit-ws without front-end normalization or redirect, which makes it less easily exploitable and a better fit for Moderate. Embargo: no Reason: This is an availability-only issue in a configuration-dependent deployment, and there are straightforward operational mitigations such as redirecting or normalizing the exact UrlRoot request before it reaches cockpit-ws. Acknowledgement: Aisle Research Vulnerability Details: Non-empty urlroot handling accepts an exact prefix match because pathhasprefix() treats either '\0' or '/' after the prefix as valid. cockpitwebrequestprocess() then strips urlroot by pointer arithmetic, so a request such as /cockpit becomes an empty string rather than /: c static gboolean pathhasprefix (const gchar path, GString prefix) { return prefix->len > 0 && strncmp (path, prefix->str, prefix->len) == 0 && (path[prefix->len] == '\0' || path[prefix->len] == '/'); } c if (self->webserver->urlroot->len && !pathhasprefix (path, self->webserver->urlroot)) { self->delayedreply = 404; } ... self->originalpath = pathcopy; self->path = pathcopy + self->webserver->urlroot->len; The default stream handler assumes the resulting path always begins with / and aborts otherwise: c gassert (request->path[0] == '/'); gsize componentend = 1 + strcspn (request->path + 1, "/"); [WebService] UrlRoot is wired into url-root in src/ws/main.c, and the registered handle-stream callbacks only claim their expected /socket or /channel/ paths. As a result, an empty path can fall through to the default stream handler before authentication. Some front-end proxies may normalize or redirect the exact prefix path before cockpit-ws sees it, so reachability depends on the deployed request path rather than being universal across all installations. Steps to reproduce: 1. Configure Cockpit with a non-empty URL root: ini [WebService] UrlRoot=/cockpit 2. Restart cockpit-ws or the service stack that launches it. 3. Send a request to the exact configured prefix without a trailing slash using a route that reaches cockpit-ws without rewriting the request first. For example, in a deployment where the request reaches the service directly: bash curl -i http://<host>:9090/cockpit Raw request equivalent: http GET /cockpit HTTP/1.1 Host: <host>:9090 If the deployment redirects plain HTTP to HTTPS before cockpit-ws handles the request, issue the same exact-path request through the front-end HTTPS endpoint instead. 4. Observe a process abort at gassert (request->path[0] == '/'). Deployments whose front-end normalizes /cockpit to /cockpit/ before forwarding may not reproduce through that route. Mitigation: Until a code fix is available, either avoid deploying a non-empty [WebService] UrlRoot where feasible, or ensure the front-end proxy or TLS terminator rewrites or redirects the exact configured prefix, for example /cockpit, to the trailing-slash form before forwarding to cockpit-ws. Proposed Fix: Normalizing an empty post-prefix path to / avoids the reachable assertion for exact-root requests, including query-bearing variants, while keeping handler behavior otherwise stable. diff diff --git a/src/ws/cockpitwebserver.c b/src/ws/cockpitwebserver.c @@ -780,6 +780,10 @@ cockpitwebrequestprocess (CockpitWebRequest self, self->path = pathcopy + self->webserver->urlroot->len; self->headers = headers; self->host = host; @@ -791,6 +795,10 @@ cockpitwebrequestprocess (CockpitWebRequest self, else self->query = ""; + + / Exact UrlRoot request (e.g. "/cockpit") yields empty suffix; normalize / + if (self->path[0] == '\0') + self->path = "/"; Optional follow-up hardening: add a regression test covering GET /path when url-root=/path. ------ This report was generated using AI technology. Always review AI-generated content prior to use
— Red Hat
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
debian/cockpitto a version that resolves this vulnerability.Fixed in 368-1 - Upgrade
Upgrade
debian/cockpitto a version that resolves this vulnerability.Fixed in 370-1 - Configuration
Avoid serving Cockpit with a non-empty [WebService] UrlRoot unless requests to the exact configured prefix are normalized to include a trailing slash before reaching cockpit-ws (e.g., rewrite/redirect GET /cockpit to GET /cockpit/).
Cockpit Web Service (cockpit-ws) [WebService] UrlRoot = / (non-empty normalization)
Event History
Frequently Asked Questions
Which deployments are exposed to this denial of service?
The affected target must run cockpit-356-1.el10 and have a non-empty [WebService] UrlRoot configuration. The vulnerable request must also be able to reach cockpit-ws without an intervening route that normalizes or redirects the URL.
Does exploiting this issue require credentials or user interaction?
No. A remote attacker can trigger the condition without authentication or user interaction by requesting the exact configured URL-root prefix without a trailing slash.
What is the practical impact of a successful attack?
cockpit-ws can terminate unexpectedly, making the Cockpit web service unavailable. The availability impact depends on a build in which g_assert() is active.