Bug 2571781

Summary: CVE-2026-91151 cockpit: Cockpit: Local privilege escalation via insecure symlink handling in public key addition helper [fedora-all]
Product: [Fedora] Fedora Reporter: Marco Benatto <mbenatto>
Component: cockpitAssignee: Jelle van der Waa <jelle>
Status: NEW --- QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: high Docs Contact:
Priority: high    
Version: rawhideCC: jelle, kkoukiou, martin, patrick, stefw, tmatus
Target Milestone: ---Keywords: Security, SecurityTracking
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard: {"flaws": ["215dd652-6695-46cf-81d8-ea9624960d61"]}
Fixed In Version: Doc Type: ---
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 2478404    

Description Marco Benatto 2026-11-11 17:33:43 UTC
Disclaimer: Community trackers are created by Red Hat Product Security team on a best effort basis. Package maintainers are required to ascertain if the flaw indeed affects their package, before starting the update process.

AI_ONLY_REPORT
package: cockpit-356-1.el10
------
Summary: Privileged Symlink Dereference in  
`pkg/users/ssh-add-public-key.sh` Allows Arbitrary Ownership/Mode Changes:  
the privileged add-key helper follows attacker-controlled `.ssh` and  
`authorized_keys` symlinks, allowing attacker-chosen ownership changes and  
related mode changes when the helper runs with an active privileged  
bridge/root context.
Requirements to exploit: A local authenticated user must be able to control  
the target account's home directory contents and must get the helper to run  
with elevated privileges, such as in an active privileged Cockpit session.  
The issue is not arbitrary `home_dir` injection; it arises from symlink  
manipulation inside the configured home path. Without a privileged  
bridge/root context, the same code path does not cross a security boundary.
Component affected: `cockpit-356-1.el10` Users "Add public key" helper,  
`pkg/users/ssh-add-public-key.sh`, invoked from  
`pkg/users/authorized-keys.js`
Version affected: `cockpit-356-1.el10` when the Users "Add public key"  
workflow is executed with an active privileged bridge/root context
Patch available: no released package fix established; proposed patch  
included below
Version fixed: unknown
Upstream coordination: Not notified.
CVSS: CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H - 7.8 (HIGH)
AV:L - The attacker needs a local authenticated account whose home  
directory contents they can control.
AC:L - Preparing the required symlink state is straightforward and does  
not require races or special timing.
PR:L - Low privileges are sufficient before exploitation.
UI:R - The vulnerable add-key action must be invoked in a session where  
the helper actually has privileged/root execution context.
S:U - The vulnerable component and the impacted resources are under the  
same host security authority.
C:H - Redirected privileged file handling can expose protected files or  
make them accessible to the attacker.
I:H - Attacker-chosen ownership changes on sensitive paths can directly  
break privilege boundaries and enable further unauthorized modification.
A:H - Ownership or mode changes on critical paths can disrupt services  
or system operation.
Impact: Important. Based on Red Hat's severity guidance, this issue can  
allow a local authenticated user to gain additional privileges by  
redirecting privileged filesystem operations to attacker-chosen paths. That  
is a direct integrity boundary break with potentially severe  
confidentiality and availability consequences once triggered. It is not  
Critical because exploitation is not remote or unauthenticated and requires  
both user interaction and a privileged execution context.
Embargo: yes
Reason: The issue provides a straightforward local privilege-escalation  
technique when the affected workflow is used in a privileged session, and  
there is no released fix yet.
Acknowledgement: Aisle Research
Vulnerability Details: The helper script performs privileged operations in  
`$2/.ssh` without checking whether `.ssh` or `authorized_keys` are symlinks:
```sh
mkdir -p "$2/.ssh"
cd "$2/.ssh"
chown $1 .
touch authorized_keys 2> /dev/null || true
chown $1 authorized_keys 2> /dev/null || true
sed -i -e '$a\' authorized_keys
cat >> authorized_keys
chown $1 authorized_keys 2> /dev/null || true
chmod 600 authorized_keys
```
The Users page reaches this helper through `cockpit.script(adder,  
[user_name, home_dir], { superuser: "try", err: "message" })`, and the  
add-key action is exposed when `user == current_user | 
!!superuser.allowed`. The `home_dir` value comes from the account record,  
so the problem is not arbitrary path input from the UI; it is privileged  
dereference of attacker-controlled symlinks inside the configured home path.
If `.ssh` is a symlink to an attacker-chosen directory, `cd "$2/.ssh"` and  
`chown $1 .` operate on the symlink target directory and can change its  
ownership under elevated privileges. Subsequent `touch`, `chown`, and  
`chmod` operations then act within that dereferenced location. An  
`authorized_keys` symlink can also influence file handling in that  
directory, although the exact final file state depends on how the  
underlying utilities handle in-place edits. The core issue is that  
privileged filesystem changes are performed on attacker-controlled paths  
without rejecting symlinks.
Steps to reproduce: The following reproducer demonstrates the deterministic  
directory-ownership change through a symlinked `.ssh` directory without  
relying on tool-specific in-place editing behavior.
1. Prepare a safe victim path and an attacker-controlled home directory:
```bash
sudo rm -rf /tmp/ssh-poc-home /tmp/ssh-poc-target
sudo mkdir -p /tmp/ssh-poc-home /tmp/ssh-poc-target
sudo chown root:root /tmp/ssh-poc-target
ln -s /tmp/ssh-poc-target /tmp/ssh-poc-home/.ssh
```
2. Confirm the initial owner:
```bash
stat -c '%U:%G %n' /tmp/ssh-poc-target
```
3. Run the helper as root with a benign test key:
```bash
printf 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestKeyForPoC\n' | \
sudo /bin/sh pkg/users/ssh-add-public-key.sh nobody /tmp/ssh-poc-home
```
4. Check the target directory again:
```bash
stat -c '%U:%G %n' /tmp/ssh-poc-target
```
Expected result: the owner of `/tmp/ssh-poc-target` changes from `root` to  
`nobody`, demonstrating that the privileged helper followed the attacker's  
`.ssh` symlink and applied `chown` to the target directory.
Mitigation: Until a fix is available, avoid using the Users "Add public  
key" workflow in a privileged session for untrusted accounts, and verify  
that the target account's `.ssh` directory and `authorized_keys` path are  
not symlinks before using the feature. Administratively managed `.ssh`  
contents that are not attacker-controlled reduce exposure.
Proposed Fix: A minimal hardening change is to reject symlinked `.ssh` and  
`authorized_keys` paths before performing privileged filesystem operations,  
canonicalize the working directory with `cd -P`, and use `chown -h`  
defensively.
```diff
— a/pkg/users/ssh-add-public-key.sh
+++ b/pkg/users/ssh-add-public-key.sh
@@
set -euf
-mkdir -p "$2/.ssh"
-cd "$2/.ssh"
+user="$1"
+home="$2"
+ssh_dir="$home/.ssh"
+
+mkdir -p – "$ssh_dir"
+[ -d "$ssh_dir" ] || { echo "Invalid .ssh directory: $ssh_dir" >&2; exit  
1; }
+[ -L "$ssh_dir" ] && { echo "Refusing symlinked .ssh directory: $ssh_dir"  
>&2; exit 1; }
+cd -P – "$ssh_dir"
-chown $1 .
+[ -e authorized_keys ] && [ -L authorized_keys ] && {
+    echo "Refusing symlinked authorized_keys" >&2
+    exit 1
+}
touch authorized_keys 2> /dev/null || true
-chown $1 authorized_keys 2> /dev/null || true
+[ -L authorized_keys ] && {
+    echo "Refusing symlinked authorized_keys" >&2
+    exit 1
+}
+chown -h "$user" .
+chown -h "$user" authorized_keys 2> /dev/null || true
sed -i -e '$a\' authorized_keys
cat >> authorized_keys
-chown $1 authorized_keys 2> /dev/null || true
+chown -h "$user" authorized_keys 2> /dev/null || true
chmod 600 authorized_keys
```
------
This report was generated using AI technology. Always review AI-generated  
content prior to use