CVE-2026-4631: Cockpit: cockpit: unauthenticated remote code execution due to ssh command-line argument injection

Published Mar 23, 2026
·
Updated

By default, Cockpit supports logging into remote machines via SSH (https://github.com/cockpit-project/cockpit/blob/main/doc/authentication.md#remote-machines). While previous Cockpit versions used the dedicated cockpit-ssh helper (based on libssh), Cockpit since version 326/327 executes "python3 -m cockpit.beiboot", which in turn invokes the OpenSSH "ssh" client to connect to remote machines. The SSH "connect to" feature is available prior to authentication, meaning an attacker with access to the Cockpit webservice can trigger the execution of ssh on the Cockpit host. To be precise: the beiboot process is spawned as part of the authentication flow, but the attacker only needs to supply an arbitrary "Authorization: Basic" header with any credentials (even invalid ones) in a request to "/cockpit+=<hostname>/login" to trigger the ssh invocation. The injected commands execute before SSH authentication completes or fails.

The security issue is that SSH connection parameters are passed down as command-line arguments to ssh without any validation or sanitization. Neither cockpit-ws (C code in cockpitauth.c / cockpitauthorize.c) nor cockpit.beiboot (Python code in beiboot.py) performs any character or format checks on the username or hostname before passing them to the ssh process. In particular, this allows an attacker to invoke ssh on the Cockpit host with an arbitrary username and hostname during the login flow.

The resulting ssh invocation looks like (simplified; additional options like -o NumberOfPasswordPrompts=1 are omitted for clarity):

arg0: ssh arg1: -l arg2: <username> arg3: <hostname> arg4: python3 -ic '# cockpit-bridge'

An attacker has full control over <username> and near-full control over <hostname> (some characters like whitespace and slashes cannot be used because the hostname is extracted from the URL path). Notably, there is no "--" separator between the ssh options and the destination argument, which enables option injection via the hostname field.

This leads to the following two vulnerabilities:

(1) Injection of malicious remote username leading to RCE

SSH allows the use of the remote username as a variable in SSH configuration files via the %r token. A potential SSH configuration could be:

Match exec "/usr/bin/test %r = blockeduser" ProxyCommand /bin/false

With this configuration, ssh executes the command "/usr/bin/test <username> = blockeduser" during connection setup. Since %r is expanded before the command is passed to the shell, an attacker can inject arbitrary shell commands through the username. For example, using the username "x; touch /tmp/flag; #" would cause ssh to execute:

/usr/bin/test x; touch /tmp/flag; # = blockeduser

The command injection occurs before ssh validates the username format. Although ssh ultimately terminates with "remote username containing invalid characters", the injected command ("touch /tmp/flag") has already been executed.

This means if the Cockpit host's sshconfig uses %r in a "Match exec" directive, Cockpit is vulnerable to unauthenticated remote code execution.

I am in parallel in contact with the OpenSSH maintainers to get this problem fixed in OpenSSH as well, though I believe it is also an issue in Cockpit for passing unverified data to ssh.

(2) Injection of malicious hostname leading to RCE

Since the hostname is passed as a positional argument to ssh without a preceding "--" separator (see viassh() in beiboot.py), an attacker can inject SSH options by supplying a hostname that starts with "-". For example, the attacker can pass "-oProxyCommand=<maliciouscommand>" as the hostname via the URL path "/cockpit+=-oProxyCommand=<maliciouscommand>/login".

ProxyCommand is an SSH client option that executes a specified program whenever SSH connects to a remote host. When the original hostname field is consumed as an option instead of a hostname, ssh interprets the next positional argument, which is "python3 -ic '# cockpit-bridge'" (the remote command), as the actual hostname. This means the malicious ProxyCommand is executed as ssh attempts to "connect" to this misinterpreted hostname.

Fortunately, OpenSSH version 9.6 introduced early hostname validation that bans shell metacharacters in command-line hostnames and usernames (https://github.com/openssh/openssh-portable/commit/7ef3787) before establishing an SSH connection. With OpenSSH >= 9.6, the command injection via "-oProxyCommand=<maliciouscommand>" fails because "python3 -ic '# cockpit-bridge'" contains invalid hostname characters (spaces, quotes, etc.), and ssh aborts before executing the ProxyCommand. Nevertheless, on older OpenSSH versions, this check is not available and <maliciouscommand> will be executed by OpenSSH in an attempt to connect to "python3 -ic '# cockpit-bridge'".

The probability that a Cockpit host is vulnerable to this depends on the OpenSSH version installed. Cockpit migrated to the beiboot/OpenSSH path in version 327 (released 2024-10-23), while OpenSSH 9.6 was released on 2023-12-18, which is roughly 10 months earlier. Systems that upgraded Cockpit to >= 327 but did not update OpenSSH to >= 9.6 would be vulnerable to unauthenticated remote code execution via hostname injection.

Potential fix:

1. Add a "--" separator before the destination argument in viassh() (beiboot.py) to prevent option injection via the hostname. This directly mitigates vulnerability (2). 2. Validate both username and hostname using a character allowlist before passing them to ssh. Examples for such validation can be found in OpenSSH's source code: validhostname() and validruser() in ssh.c. This mitigates both vulnerabilities (1) and (2).

Summary:

While the preconditions for these vulnerabilities will likely affect only a subset of Cockpit installations, the impact is critical: unauthenticated remote code execution on the Cockpit host. An attacker with network access to the Cockpit webservice can trigger the exploit with a single crafted HTTP request to the login endpoint. No valid credentials are required, as the injection occurs during the authentication flow before SSH authentication completes.

Other sources

Cockpit's remote login feature passes user-supplied hostnames and usernames from the web interface to the SSH client without validation or sanitization. An attacker with network access to the Cockpit web service can craft a single HTTP request to the login endpoint that injects malicious SSH options or shell commands, achieving code execution on the Cockpit host without valid credentials. The injection occurs during the authentication flow before any credential verification takes place, meaning no login is required to exploit the vulnerability.

— MITRE

Affected Software

2 affected components
Cockpit project Cockpit>=326<327
Cockpit project Cockpit>=327<=

Event History

Mar 23, 2026
Data Sourced
via Red Hat·08:25 AM
DescriptionSeverityAffected Software
Apr 7, 2026
CVE Published
via MITRE·04:30 PM
Data Sourced
via MITRE·04:30 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·05:16 PM
DescriptionSeverityWeakness
Apr 18, 2026
Exploit Published
via GitHub·08:30 PM

Frequently Asked Questions

1

What is the severity of CVE-2026-4631?

CVE-2026-4631 has a high severity rating due to the potential for unauthenticated remote code execution.

2

How do I fix CVE-2026-4631?

To fix CVE-2026-4631, update Cockpit to the latest version that addresses this vulnerability.

3

What versions of Cockpit are affected by CVE-2026-4631?

CVE-2026-4631 affects Cockpit versions starting from 327.

4

What kind of attacks are possible with CVE-2026-4631?

CVE-2026-4631 allows attackers to execute arbitrary commands on a remote system due to SSH command-line argument injection.

5

Is authentication required to exploit CVE-2026-4631?

No, CVE-2026-4631 can be exploited without authentication, making it particularly dangerous.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203