Debian GNU/Linux · Filesystem & permissions

Review setuid and setgid programs and keep only those that are needed

When it fails: Unexpected setuid or setgid programs are present. Each setuid or setgid program runs with extra privileges for any user, so one flaw or one planted binary gives those privileges away.

CB-DEB-FS-010mediumactivepartialprofile core

As released in v0.1.1 beta · pre-release. Current state.

Description

A program with the setuid (or setgid) bit runs with the rights of its owner (or group), usually root, whoever starts it. Every such program on local filesystems is known and needed. The check lists the ones that do not match {{ allowed }}, a list of shell patterns that holds the setuid and setgid programs shipped by common Debian packages. A human still reviews the full list.

A fresh Debian 12 or 13 cloud image has 16 or 17 such programs, all in the default list. dpkg-statoverride keeps a removed bit across package upgrades; a plain chmod is undone at the next upgrade of the package. The check passes as "review": it confirms there is nothing unexpected, not that every listed program is needed.

Rationale

Setuid root programs are the main way for a local user to escalate privileges: a bug in any of them (pkexec, sudo and others have had several) gives root. Attackers also leave a setuid copy of a shell behind as a backdoor. Fewer such programs mean less attack surface, and a reviewed list makes a new one stand out.

Impact

Removing the setuid bit from a program stops non-root users from using it (for example chfn, chsh or newgrp). Check who needs each program before removing it.

Parameters

ParameterCoreServerServer hardenedDesktopDesktop hardenedBounds
allowedlist. Shell patterns of setuid and setgid programs accepted without review./usr/bin/at, /usr/bin/chage, /usr/bin/chfn, /usr/bin/chsh, /usr/bin/crontab, /usr/bin/dotlockfile, /usr/bin/expiry, /usr/bin/fusermount, /usr/bin/fusermount3, /usr/bin/gpasswd, /usr/bin/mount, /usr/bin/newgrp, /usr/bin/passwd, /usr/bin/pkexec, /usr/bin/ssh-agent, /usr/bin/su, /usr/bin/sudo, /usr/bin/umount, /usr/bin/wall, /usr/bin/write, /usr/bin/bsd-write, /usr/lib/dbus-1.0/dbus-daemon-launch-helper, /usr/lib/openssh/ssh-keysign, /usr/lib/polkit-1/polkit-agent-helper-1, /usr/lib/*/utempter/utempter, /usr/lib/xorg/Xorg.wrap, /usr/sbin/exim4, /usr/sbin/pam_extrausers_chkpwd, /usr/sbin/unix_chkpwd/usr/bin/at, /usr/bin/chage, /usr/bin/chfn, /usr/bin/chsh, /usr/bin/crontab, /usr/bin/dotlockfile, /usr/bin/expiry, /usr/bin/fusermount, /usr/bin/fusermount3, /usr/bin/gpasswd, /usr/bin/mount, /usr/bin/newgrp, /usr/bin/passwd, /usr/bin/pkexec, /usr/bin/ssh-agent, /usr/bin/su, /usr/bin/sudo, /usr/bin/umount, /usr/bin/wall, /usr/bin/write, /usr/bin/bsd-write, /usr/lib/dbus-1.0/dbus-daemon-launch-helper, /usr/lib/openssh/ssh-keysign, /usr/lib/polkit-1/polkit-agent-helper-1, /usr/lib/*/utempter/utempter, /usr/lib/xorg/Xorg.wrap, /usr/sbin/exim4, /usr/sbin/pam_extrausers_chkpwd, /usr/sbin/unix_chkpwd/usr/bin/at, /usr/bin/chage, /usr/bin/chfn, /usr/bin/chsh, /usr/bin/crontab, /usr/bin/dotlockfile, /usr/bin/expiry, /usr/bin/fusermount, /usr/bin/fusermount3, /usr/bin/gpasswd, /usr/bin/mount, /usr/bin/newgrp, /usr/bin/passwd, /usr/bin/pkexec, /usr/bin/ssh-agent, /usr/bin/su, /usr/bin/sudo, /usr/bin/umount, /usr/bin/wall, /usr/bin/write, /usr/bin/bsd-write, /usr/lib/dbus-1.0/dbus-daemon-launch-helper, /usr/lib/openssh/ssh-keysign, /usr/lib/polkit-1/polkit-agent-helper-1, /usr/lib/*/utempter/utempter, /usr/lib/xorg/Xorg.wrap, /usr/sbin/exim4, /usr/sbin/pam_extrausers_chkpwd, /usr/sbin/unix_chkpwd/usr/bin/at, /usr/bin/chage, /usr/bin/chfn, /usr/bin/chsh, /usr/bin/crontab, /usr/bin/dotlockfile, /usr/bin/expiry, /usr/bin/fusermount, /usr/bin/fusermount3, /usr/bin/gpasswd, /usr/bin/mount, /usr/bin/newgrp, /usr/bin/passwd, /usr/bin/pkexec, /usr/bin/ssh-agent, /usr/bin/su, /usr/bin/sudo, /usr/bin/umount, /usr/bin/wall, /usr/bin/write, /usr/bin/bsd-write, /usr/lib/dbus-1.0/dbus-daemon-launch-helper, /usr/lib/openssh/ssh-keysign, /usr/lib/polkit-1/polkit-agent-helper-1, /usr/lib/*/utempter/utempter, /usr/lib/xorg/Xorg.wrap, /usr/sbin/exim4, /usr/sbin/pam_extrausers_chkpwd, /usr/sbin/unix_chkpwd/usr/bin/at, /usr/bin/chage, /usr/bin/chfn, /usr/bin/chsh, /usr/bin/crontab, /usr/bin/dotlockfile, /usr/bin/expiry, /usr/bin/fusermount, /usr/bin/fusermount3, /usr/bin/gpasswd, /usr/bin/mount, /usr/bin/newgrp, /usr/bin/passwd, /usr/bin/pkexec, /usr/bin/ssh-agent, /usr/bin/su, /usr/bin/sudo, /usr/bin/umount, /usr/bin/wall, /usr/bin/write, /usr/bin/bsd-write, /usr/lib/dbus-1.0/dbus-daemon-launch-helper, /usr/lib/openssh/ssh-keysign, /usr/lib/polkit-1/polkit-agent-helper-1, /usr/lib/*/utempter/utempter, /usr/lib/xorg/Xorg.wrap, /usr/sbin/exim4, /usr/sbin/pam_extrausers_chkpwd, /usr/sbin/unix_chkpwd

The value used is your override (tailoring file), else the profile's, else the one of the profile it extends, else the default. Bounds limit what an override may set.

Audit

  1. For each local filesystem listed by findmnt -knr -o TARGET -t ext2,ext3,ext4,xfs,btrfs,jfs,f2fs,vfat,exfat,tmpfs, run find <mount point> -xdev -type f -perm /6000 -exec ls -l {} +.
  2. For each program, check that it comes from a package (dpkg -S <program>), that dpkg --verify <package> reports no change, and that it is needed on this system.

Automated: every check must pass. Scanners report each check by its id.

unexpected

Setuid and setgid files on local filesystems that match none of the allowed patterns.

script: |
  all=$(for m in $(findmnt -knr -o TARGET -t ext2,ext3,ext4,xfs,btrfs,jfs,f2fs,vfat,exfat,tmpfs); do
    find "$m" -xdev -type f -perm /6000 -print 2>/dev/null
  done | sort -u)
  set -f
  rc=0 n=0
  for f in $all; do
    n=$((n + 1))
    ok=0
    for p in $CB_ALLOWED; do
      # shellcheck disable=SC2254 # the pattern is the point
      case $f in $p) ok=1; break ;; esac
    done
    [ "$ok" = 1 ] && continue
    echo "unexpected: $(stat -c '%A %U:%G' "$f") $f"
    rc=1
  done
  echo "$n setuid/setgid file(s) in total"
  exit $rc

Remediation

For each unexpected program, and for listed programs that this system does not need:

  1. If it belongs to no package (dpkg -S finds nothing) or dpkg --verify reports it as changed, treat it as a possible compromise and investigate before deleting it.
  2. If its package is not needed, purge the package.
  3. Otherwise remove the bit in a way that survives upgrades: dpkg-statoverride --update --add root root 0755 <program>.
  4. Add programs that are needed and reviewed to {{ allowed }} in the tailoring file.

References

Mappings

FrameworkIDRelationNote
ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0R56equivalent
ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0R57partialR57 asks to remove the setuid root bit wherever possible; ours requires the review, the removal stays a local decision.
NIST SP 800-53 Rev. 55.1.1AC-6related
NIST SP 800-53 Rev. 55.1.1CM-7related

How this control relates to the other framework's: equivalent, stricter, looser, partial or related.

Threats mitigated

People and lifecycle

Authors
Verified2026-10-18 by Sn0wAlice on 12, Proxmox VM 922, Debian 12 genericcloud image, kernel 6.1.0-54-cloud-amd64. Review on fresh install (17 files on 12, 16 on 13, all allowed); setuid copy in /usr/local/bin reported as unexpected.
Verified2026-10-18 by Sn0wAlice on 13, Proxmox VM 932, Debian 13 genericcloud image, kernel 6.12.113+deb13-cloud-amd64. Review on fresh install (17 files on 12, 16 on 13, all allowed); setuid copy in /usr/local/bin reported as unexpected.
Introduced inv0.1.0
Created, updated2026-10-18, 2026-10-18
Translationsfr