Skip to content

install --backup has no source-is-backup guard and silently destroys the source

Low
sylvestre published GHSA-x2p7-fq8x-g67j Aug 7, 2026

Package

cargo uu_install (Rust)

Affected versions

<= 0.9.0

Patched versions

0.10.0

Description

Summary

install --backup=simple is supposed to refuse an operation when creating the destination's backup would overwrite the source file. install performs no such check at all: it destroys the source file and exits 0 with no diagnostic. Unlike the mv issue I reported earlier, no spelling mismatch is required — the plain form install --backup=simple a~ a is unprotected. GNU coreutils refuses every such case with a non-zero exit and an error.

Per SECURITY.md this is both a bypass of a documented safety guard and an unintended destructive action — a divergence from GNU where the check "fails open" instead of erroring.

Details

src/uu/install/src/install.rs imports uucore::backup_control and computes a backup path at install.rs:918 via backup_control::get_backup_path, but never performs any source-is-backup check before taking the backup:

$ grep -n source_is_target_backup src/uu/install/src/install.rs
$          # no output

Because the check is absent rather than incorrect, every spelling of the destination fails — a, ./a, $PWD/a alike.

Suggested fix. cp already does this correctly — src/uu/cp/src/cp.rs:2121:

let backup_path = backup_control::get_backup_path(options.backup, dest, &options.backup_suffix);
if let Some(backup_path) = backup_path {
    if paths_refer_to_same_file(source, &backup_path, true) {
        return Err(translate!("cp-error-backing-up-destroy-source", ...).into());
    }
    ...
}

install already computes the backup path via get_backup_path; the missing piece is the uucore::fs::paths_refer_to_same_file guard before the backup is taken.

PoC

Verified on:

  • 0.9.0, release tag 840c36d (2026-05-29) — the latest release
  • main tip f66e155d80df3d82798324726e460675a02c5cd5 (2026-07-27)

Ubuntu 24.04.2 LTS, Linux 6.8.0 x86_64, ext4. Console output captured with LANG=C.

No special configuration. Default build, no environment variables, any filesystem — the defect is filesystem- and platform-independent. The only requirement is --backup=simple (or -b with the default suffix) and a source named <destination><suffix>.

$ cd "$(mktemp -d)"
$ : > a                     # destination, empty
$ echo payload > a~         # source, holds the only copy of the data

$ install --backup=simple a~ a ; echo "exit=$?"
exit=0

$ cat a ; cat a~

payload no longer exists anywhere.

Unlike mv, no spelling mismatch is needed — the same happens with ./a as the destination:

$ install --backup=simple a~ ./a ; echo "exit=$?"
exit=0

Both GNU coreutils 9.7 and 9.11 refuse both forms:

$ install --backup=simple a~ a ; echo "exit=$?"
install: backing up 'a' might destroy source;  'a~' not copied
exit=1

Impact

For install --backup=simple a~ a:

  1. The destination's backup is created: a is renamed to a~ — this overwrites the source.
  2. The copy proceeds from a~, which no longer holds the original data.

The destination ends up unchanged, the source is gone, and the exit status is 0. The operation reports success while doing the opposite of what was requested.

Because the exit code is 0, defensive idioms provide no protection:

install --backup=simple "$src" "$dst" || rollback   # rollback never runs
set -e; install --backup=simple "$src" "$dst"       # never aborts

Concrete case:

install --backup=simple /usr/local/bin/app~ /usr/local/bin/app
# exit 0, reported as success
# app unchanged; the retained previous version destroyed

Rolling back to the retained previous version leaves the current binary in place and destroys the copy that was being rolled back to.

Security impact.

Recovery fails at the moment it is exercised. Restoring from a backup is what an operator reaches for after a file is tampered with or misconfigured. Here it leaves the suspect file live and consumes the known-good copy, so there is no second attempt.

Remediation automation cannot detect it. Exit 0 satisfies || rollback, set -e, and configuration-management error handling alike, so a script records a restore that never happened and carries on — discarding a staging copy, or restarting a service to pick up a binary that was never put in place.

The pre-change artifact is destroyed. Backup files are often the only on-disk record of a file's prior contents, and the baseline an investigator would diff against after an incident.

The protection is absent, not bypassed. No spelling mismatch, special permissions, timing, or crafted input is needed — the plain form fails (CWE-693, a protection mechanism that is missing rather than defeated). install is used heavily in make install, packaging scripts, and configuration management, frequently as root, where --backup exists specifically to retain the previous version of a file being replaced.

My Acknowledgement Information

Hongkai Chen of SEFCOM Lab at Arizona State University

Severity

Low

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Local
Attack complexity
Low
Privileges required
Low
User interaction
Required
Scope
Unchanged
Confidentiality
None
Integrity
Low
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N

CVE ID

No known CVE

Weaknesses

Improper Resolution of Path Equivalence

The product is vulnerable to file system contents disclosure through path equivalence. Path equivalence involves the use of special characters in file and directory names. The associated manipulations are intended to generate multiple names for the same object. Learn more on MITRE.

Protection Mechanism Failure

The product does not use or incorrectly uses a protection mechanism that provides sufficient defense against directed attacks against the product. Learn more on MITRE.

Credits