Jul 6, 2026·6 min read·2 visits
A vulnerability in uutils/coreutils chmod allows local bypass of '--preserve-root' safety checks using unnormalized paths like '/../', leading to recursive root permission destruction.
A path validation bypass vulnerability exists in the chmod utility of uutils/coreutils before version 0.6.0. The '--preserve-root' safety mechanism relies on a literal string comparison, allowing local users to bypass root directory protection via unnormalized paths (such as '/../' or symbolic links) and recursively alter system-wide permissions.
The uutils/coreutils package is a cross-platform rewrite of the GNU coreutils suite in Rust. The chmod utility is a core component used to modify file and directory permissions across different filesystems. When operating in recursive mode via the -R or --recursive flags, the utility poses a significant risk to system stability if executed on the root directory. To protect against accidental system-wide permission modifications, both GNU coreutils and uutils/coreutils implement a safety mechanism named --preserve-root which is enabled by default.
This safety mechanism is designed to abort execution immediately if the target of a recursive command is identified as the filesystem root (/). However, a path validation bypass vulnerability exists in the chmod utility of uutils/coreutils prior to version 0.6.0. Because the software fails to canonicalize paths before performing the root protection check, attackers or local users can circumvent the validation logic. This bypass allows the utility to execute destructive operations on the root directory, causing system-wide permission loss.
The vulnerability is classified as CWE-22 (Improper Limitation of a Pathname to a Restricted Directory). It exposes systems to complete denial of service and structural breakdown if a recursive chmod command is executed on paths that resolve logically to root but bypass literal checks.
The root cause of this vulnerability lies in the implementation of the path comparison check inside the recursive validator in src/uu/chmod/src/chmod.rs. To identify if the user-supplied target path points to the filesystem root, the utility performs a direct, literal comparison: file == Path::new("/"). This comparison is lexical and syntax-dependent rather than logical or semantic.
On UNIX and Linux operating systems, multiple syntactically unique paths resolve to the exact same physical directory. Specifically, the path /../ refers directly to the root directory because the parent directory of the root is recursively evaluated as the root itself. Similarly, redundant path delimiters (such as //) or relative-path tokens (such as /./) are resolved by the OS kernel to the root directory during system calls.
Because the comparison check in chmod.rs only verifies if the unnormalized string or path is strictly equal to /, it fails to recognize /../ or // as equivalent paths. As a result, when an execution is triggered with /../ as the argument, the conditional block evaluating the safety guard returns false, thereby authorizing the recursive directory traversal and permission changes.
An examination of the vulnerable code segment in src/uu/chmod/src/chmod.rs shows the reliance on a literal check. The snippet below highlights the vulnerable logic before patch application:
// Vulnerable check in chmod.rs
if self.recursive && self.preserve_root && file == Path::new("/") {
return Err(ChmodError::PreserveRoot("/".into()).into());
}The fix introduced in Git commit 413055b378fa6fe2299c5e5f538c8e6e841ab810 replaces this literal comparison with a dedicated helper function Self::is_root(file) that leverages absolute path resolution:
// Patched check in chmod.rs
if self.recursive && self.preserve_root && Self::is_root(file) {
return Err(ChmodError::PreserveRoot("/".into()).into());
}
// Helper function implementing canonicalization
fn is_root(file: impl AsRef<Path>) -> bool {
matches!(fs::canonicalize(&file), Ok(p) if p == Path::new("/"))
}The function is_root invokes std::fs::canonicalize(), which resolves all intermediate symbolic links, redundant separators, and relative directory traversals like .. and .. The resulting absolute path p is then verified against the literal root path. If the resolved path matches /, the safety guard successfully triggers, throwing an error and terminating the command before execution begins.
Exploitation of this vulnerability requires local shell access to execute the chmod utility, or the ability to influence arguments passed to a recursive execution of chmod. The most immediate attack scenario involves an unprivileged local user or an administrative account mistakenly executing a recursive permission change. Under normal conditions, attempting to execute a recursive permission deletion on the root directory is blocked by the default safety configuration.
To bypass this check, an operator or local actor can execute the following command:
chmod -R --preserve-root 000 /../Because the utility fails to canonicalize /../, it bypasses the safety guard. The OS then processes the target as the filesystem root, recursively descending through every directory starting from the root. This results in the complete loss of all file permissions, rendering the operating system inoperable. Symbolic links pointing to / can also be exploited to trigger similar outcomes if the link itself is targeted during execution.
The security implications of bypassing --preserve-root are substantial, as it leads directly to local denial of service and structural system failure. If executed with high privileges, such as root or sudo, the system loses all capability to load shared libraries, run system binaries, or authenticate users due to the destruction of standard UNIX file permissions (e.g., setuid flags on /bin/sudo or read permissions on configuration files).
While the fix in version 0.6.0 resolves simple path-traversal bypasses using canonicalization, certain advanced vectors remain relevant for security engineers to consider. For example, a Time-of-Check to Time-of-Use (TOCTOU) race condition is theoretically possible. If an operator starts a recursive chmod on a benign directory, an attacker with write access to the parent directories could swap the target directory with a symbolic link to the root directory during the active traversal, bypassing the initial canonicalization check.
Additionally, std::fs::canonicalize() requires that the path elements exist and are accessible. If path resolution fails due to intermediate permission restrictions, the helper function is_root evaluates to false. A more complete fix, similar to the implementation in GNU coreutils, would compare the device identifier (st_dev) and inode number (st_ino) of the target path against the root mount point to ensure absolute identity resolution regardless of the directory string state.
The primary remediation path is upgrading uutils/coreutils to version 0.6.0 or later. This release integrates the canonicalization fix that secures the --preserve-root guard against directory traversal bypass vectors. If immediate upgrading is not possible, organizations should deploy wrapper scripts or monitoring rules to detect and block recursive execution of chmod containing parent directory tokens.
Detection of exploit attempts or accidental execution can be achieved by monitoring shell history and system audit logs for suspicious execution parameters. Specifically, look for command invocations matching the pattern chmod -R or chmod --recursive followed by arguments containing /.. or other non-standard root path representations.
In highly sensitive environments, administrators can configure system policies (such as AppArmor or SELinux) to restrict the execution of recursive permission changes on system-level directories. This restricts the potential blast radius of both accidental errors and malicious exploitation.
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
uutils/coreutils uutils | < 0.6.0 | 0.6.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| Attack Vector | Local (AV:L) |
| CVSS v3.1 Score | 7.3 |
| EPSS Score | 0.00175 |
| EPSS Percentile | 7.13% |
| Impact | Local Denial of Service / Structural Permissions Failure |
| Exploit Status | Proof of Concept Available |
| CISA KEV Status | Not Listed |
The product uses unsanitized input to construct a pathname that should be within a restricted directory, but it does not properly resolve or neutralize paths that traverse outside of the restricted directory.
An improper access control and mass assignment vulnerability in Scriban allows templates to write to arbitrary, restricted CLR properties (including private, internal, and init-only properties) of context-bound objects, causing unexpected state mutations on the host application heap.
A critical heap-based out-of-bounds write vulnerability exists in Open Babel 3.1.1 and master commit 530dbfa3 within the parsing of Translation Vectors in the MOPAC output file format parser. By supplying a crafted MOPAC file containing more than three translation vector entries under the Unit Cell Translation block, an attacker can corrupt heap memory. This vulnerability can lead to arbitrary code execution or denial of service.
Adobe ColdFusion versions 2025.9 and 2023.20 and earlier are affected by an Unrestricted Upload of File with Dangerous Type vulnerability (CWE-434). An unauthenticated remote attacker can exploit this flaw to upload malicious ColdFusion Markup Language (CFML) files directly into web-accessible directories. Accessing the uploaded script triggers arbitrary code execution in the security context of the running service account.
CVE-2026-46599 (also identified by Go vulnerability alias GO-2026-5032) is a high-severity denial-of-service vulnerability in the Go image repository, specifically within the TIFF decoder's PackBits decompression engine. A lack of resource limits during the parsing of Run-Length Encoded PackBits streams allows an attacker to construct a crafted TIFF image that achieves significant decompression amplification. This flaw enables an unauthenticated remote attacker to exhaust system resources, leading to an Out-of-Memory crash or a prolonged application hang.
A property shadowing vulnerability exists in protobufjs where schema-derived names can collide with and overwrite runtime-critical internal helper properties. This issue leads to uncaught runtime exceptions and crash-based Denial of Service.
An integer truncation vulnerability (CWE-197) exists in SQLite before version 3.50.2 during the processing of aggregate queries with more than 32,767 distinct column references. This causes an internal 32-bit counter to truncate to a signed 16-bit integer, producing negative values that cause out-of-bounds heap operations in release builds.