Bug 2465632 (CVE-2026-91203) - CVE-2026-91203 cockpit-files: cockpit-files: Arbitrary file ownership and permission modification via symlink race condition
Summary: CVE-2026-91203 cockpit-files: cockpit-files: Arbitrary file ownership and per...
Keywords:
Status: NEW
Alias: CVE-2026-91203
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Product Security DevOps Team
QA Contact:
URL:
Whiteboard:
Depends On: 2537071
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-05-04 15:54 UTC by OSIDB Bzimport
Modified: 2026-09-18 19:28 UTC (History)
3 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-05-04 15:54:51 UTC
AI_ONLY_REPORT
package: cockpit-files-36-1.el10
------
Summary: Symlink Race in chown/chmod Operations: privileged pathname-based  
ownership and permission changes can be redirected through a symlink swap  
in attacker-writable directories
Requirements to exploit: A local attacker must be able to modify entries in  
the directory being operated on, a Cockpit Files session must perform one  
of the affected operations with `superuser: "require"` or with  
`superuser: "try"` successfully elevated, and the attacker must win a  
timing race that replaces the intended pathname with a symlink before the  
privileged `chown` or `chmod` runs.
Component affected: `cockpit-files-36-1.el10`, privileged file metadata  
operations in `src/dialogs/create-file.tsx`, `src/dialogs/mkdir.tsx`,  
`src/upload-button.tsx`, `src/dialogs/copyPasteOwnership.tsx`, and  
`src/dialogs/permissions.tsx`
Version affected: `cockpit-files-36-1.el10`
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:H/PR:L/UI:R/S:U/C:N/I:H/A:H - 6.4 (MEDIUM)
AV:L - Exploitation requires local access to a writable directory  
processed by the application.
AC:H - The attacker must win a symlink race against a privileged  
filesystem operation.
PR:L - The attacker needs the ability to create or replace entries in  
the target directory.
UI:R - A privileged user must trigger the affected file creation,  
upload, ownership, or permission change flow.
S:U - The impact remains within the same system security scope.
C:N - The observed effect is unauthorized metadata change rather than  
direct information disclosure.
I:H - Ownership or mode changes on an unintended target can materially  
alter system or application state.
A:H - Incorrect privileged metadata changes can render files or services  
unusable.
Impact: Moderate. The flaw can affect integrity and availability in a  
meaningful way, but exploitation is not straightforward: it is local-only,  
depends on a privileged user operating on an attacker-writable path, and  
requires winning a race. Under Red Hat's severity guidance, this is better  
classified as Moderate than Important because the security impact is real  
but workflow- and configuration-dependent and less easily exploitable.
Embargo: no
Reason: The issue appears to be a local race condition with non-trivial  
prerequisites and practical mitigations, so it does not appear to warrant  
embargo handling.
Acknowledgement: Aisle Research
Vulnerability Details: Several code paths perform privileged `chown` or  
`chmod` operations on pathnames after separate create, selection, copy, or  
upload steps. When the acted-on directory is attacker-writable, that  
pathname can be replaced with a symlink before the privileged metadata  
change executes. In that case, the operation can be redirected to an  
unintended target.
The following exact call sites illustrate the pattern:
```tsx
// src/dialogs/create-file.tsx:45
await cockpit.spawn(["chown", owner, filename], { superuser: "require" });
// src/dialogs/mkdir.tsx:45
await cockpit.spawn(["chown", owner, path], opts);
// src/upload-button.tsx:268
await cockpit.spawn(["chown", owner, destination], { superuser: "try" });
// src/dialogs/copyPasteOwnership.tsx:44-49
await cockpit.spawn([
"chown", "--recursive", ownerStr, ...clipboard.files.map(file => dstPath  
+ "/" + file.name),
], { superuser: "require" });
// src/dialogs/permissions.tsx:170-174
await cockpit.spawn(["chmod", "-R", mode_to_args(mode), full_path], {  
superuser: "try", err: "message" });
await cockpit.spawn(["chown", "-R", owner + ":" + group, full_path], {  
superuser: "try", err: "message" });
// src/dialogs/permissions.tsx:191-192
await cockpit.spawn(["chmod", mode.toString(8), ...file_paths], {  
superuser: "try", err: "message" });
```
For `chown`, the absence of `--no-dereference` means a symlink operand is  
resolved to its target. For `chmod`, operating on a symlink pathname  
likewise affects the referenced file rather than the link itself. Because  
these operations are issued against mutable pathnames rather than stable  
descriptors, an attacker who controls the directory namespace can attempt a  
symlink swap between the earlier UI action and the later privileged  
metadata change.
The practical impact depends on runtime conditions. If the affected flow is  
used only in directories not writable by untrusted users, or if privileged  
escalation is unavailable, exploitability is substantially reduced. Where a  
privileged user does operate on attacker-writable directories, the bug can  
result in unintended ownership or permission changes on arbitrary files  
reachable through the symlink target.
Steps to reproduce:
1. Use a Cockpit session where privileged filesystem operations are  
available, so that `superuser: "require"` or `superuser: "try"` results in  
an elevated `chown` or `chmod`.
2. Choose a directory writable by a low-privileged attacker and accessible  
through the Files UI.
3. Select one affected flow, for example creating a file with an owner,  
creating a directory with an owner, uploading with owner adjustment, or  
applying recursive ownership or permission changes.
4. In parallel, continuously replace the intended pathname in that writable  
directory with a symlink to a chosen target file.
5. Trigger the UI action as the privileged user.
6. Observe that the target file's ownership or mode changes, rather than  
only the originally intended filesystem object.
Mitigation: Until a fix is available, avoid using privileged ownership or  
permission changes in directories writable by untrusted users. Where  
possible, restrict or disable superuser-backed file operations for shared  
writable paths. Operationally, prefer workflows that perform metadata  
changes only on trusted directories.
Proposed Fix: Add `--no-dereference` and `--` to the affected `chown` and  
`chmod` invocations so that symlink operands are not followed on these  
path-based operations. A minimal patch is below.
```diff
diff --git a/src/dialogs/create-file.tsx b/src/dialogs/create-file.tsx
@@
await cockpit.spawn(["chown", owner, filename], { superuser: "require" });
+ await cockpit.spawn(["chown", "-no-dereference", owner, "-", filename],  
{ superuser: "require" });


diff --git a/src/dialogs/mkdir.tsx b/src/dialogs/mkdir.tsx
@@
await cockpit.spawn(["chown", owner, path], opts);
+ await cockpit.spawn(["chown", "-no-dereference", owner, "-", path],  
opts);


diff --git a/src/upload-button.tsx b/src/upload-button.tsx
@@
await cockpit.spawn(["chown", owner, destination], { superuser: "try" });
+ await cockpit.spawn(["chown", "--no-dereference", owner, "--",  
destination], { superuser: "try" });


diff --git a/src/dialogs/copyPasteOwnership.tsx  
b/src/dialogs/copyPasteOwnership.tsx
@@
"chown", "--recursive", ownerStr, ...clipboard.files.map(file => dstPath  
+ "/" + file.name),
+ "chown", "--no-dereference", "--recursive",  
ownerStr, "--", ...clipboard.files.map(file => dstPath + "/" + file.name),


diff --git a/src/dialogs/permissions.tsx b/src/dialogs/permissions.tsx
@@
await cockpit.spawn(["chmod", "-R", mode_to_args(mode), full_path], {  
superuser: "try", err: "message" });

await cockpit.spawn(["chown", "-R", owner + ":" + group, full_path], {  
superuser: "try", err: "message" });
+ await cockpit.spawn(["chmod", "--no-dereference", "-R",  
mode_to_args(mode), "--", full_path], { superuser: "try", err: "message" });
+ await cockpit.spawn(["chown", "--no-dereference", "-R", owner + ":" +  
group, "--", full_path], { superuser: "try", err: "message" });


@@
await cockpit.spawn(["chmod", mode.toString(8), ...file_paths], {  
superuser: "try", err: "message" });
+ await cockpit.spawn(["chmod", "--no-dereference",  
mode.toString(8), "--", ...file_paths], { superuser: "try", err: "message"  
});
```


------
This report was generated using AI technology. Always review AI-generated  
content prior to use


Note You need to log in before you can comment on or make changes to this bug.