SECCHECK(1)toolbelt manualSECCHECK(1)

seccheck

A quick security check of this machine, with fixes.

Synopsis

seccheck [options]

Description

seccheck runs 12 checks on the settings that matter most on a Linux desktop or small server, and gives each one a verdict. PASS means the setting is safe. WARN means it is weaker than it should be. FAIL means it leaves a real hole. SKIP means the check could not run here. Every WARN and FAIL comes with the exact command or setting that fixes it.

It is a first look, not an audit. It checks the common mistakes, such as a firewall that is off, sshd taking passwords, a private key others can read, or security updates left waiting. It does not scan for malware, read every config file, or test services from the outside.

seccheck only reads. It never changes a setting, never installs anything, never runs sudo itself, and never talks to the network. The fix lines are for you to run once you have read them.

Running as root or not

Most checks work as a normal user. Two need root to read their files on most distros, sudo (for /etc/sudoers) and sometimes ssh (when /etc/ssh/sshd_config or an included file is private). As a normal user those checks say SKIP and name the file they could not read, and the summary counts them.

SKIP  sudo          needs root to read /etc/sudoers
12 checks: 5 pass, 4 warn, 1 fail, 2 skipped (1 need root)
To run them too: sudo seccheck

Run sudo seccheck for the full picture. As root, the ~/.ssh check looks at the home folder of the user who ran sudo, not at root's own.

The output

Each result is one line with the verdict, the check name and what it found. Fix lines follow under a WARN or FAIL, marked fix. A check that found several things, such as open ports, lists them under each other.

The last line counts the verdicts. With -q it is the only line.

Checks

CheckLabelWhat it reads
firewallfirewallfirewalld, ufw or nftables, whichever is installed
macselinux, apparmor or macSELinux mode or the AppArmor module
updatesupdatespending security updates, from the package lists on disk
sshssh password, ssh rootthe sshd config and every file it includes
securebootsecure bootthe UEFI secure boot state
encryptionencryptionwhether / sits on a LUKS encrypted device
portsopen portsTCP ports listening on the network
sudosudosudo rules that need no password
sshdir~/.sshmodes of ~/.ssh, private keys and authorized_keys
screenlockscreen lockthe desktop's lock and idle settings
pathPATHfolders in PATH others can write to
etc/etc filesfiles in /etc others can write to

seccheck --list prints the same list with a line on each.

firewall

seccheck looks for firewalld first, then ufw, then an nftables service.

With none of them running, it is a WARN, with the install line for the firewall your distro ships, firewalld on Fedora and openSUSE and ufw elsewhere.

A firewall matters most on a laptop that joins other people's networks. On a machine behind a home router, it is a second wall behind the first.

mac

Mandatory access control limits what a program can do even when it runs as root. Fedora and RHEL use SELinux. Debian, Ubuntu and openSUSE use AppArmor.

--only selinux and --only apparmor both run this check.

updates

This check asks the package manager what it would upgrade, without downloading anything and without taking the package lock, so it is safe to run while an update runs.

Package managerCommandSecurity updates are
aptapt-get -s dist-upgradepackages from a -security suite
dnfdnf -C updateinfo list --securityadvisories marked /Sec.
zypperzypper list-patches --category securitypatches marked needed
pacmanpacman -Qunot marked, every update counts
apkapk version -l '<'not marked, every update counts

Any pending security update is a FAIL. The fix is pkg upgrade. On apt, seccheck also warns when the package lists are more than 3 days old, because then it cannot know about new updates. On pacman and apk, pending updates are a WARN, because those tools do not say which ones fix security problems.

The check reads the lists already on disk. It does not refresh them, so run sudo apt update or its equal first for a current answer.

ssh

This check runs only when sshd is running, as ssh.service, sshd.service or a socket unit. With no sshd, it passes.

seccheck reads /etc/ssh/sshd_config the way sshd does. It follows each Include line in place, in order, and keeps the first value it finds for each setting, because sshd does the same. Lines inside a Match block apply only to some connections, so they are skipped.

The fix tells you where to put the line. When the config includes /etc/ssh/sshd_config.d/, the fix names /etc/ssh/sshd_config.d/00-local.conf. The 00 matters. sshd keeps the first value it reads, and files in that folder load in name order, so a line in 50-local.conf would lose to a 50-cloud-init.conf that sets the opposite. After the change, svc restart ssh applies it. Keep your current session open until you have tested a new login.

secureboot

On a UEFI machine, secure boot must be on. It stops a changed boot loader or kernel from starting. seccheck asks mokutil --sb-state, or reads the SecureBoot EFI variable when mokutil is missing. A BIOS machine has no secure boot, so the check says SKIP.

Turning it on is a firmware setting. With it on, kernel modules you build yourself, such as the NVIDIA driver or VirtualBox, must be signed, which most distros set up for you through a MOK key.

encryption

/ must sit on a LUKS encrypted device. seccheck asks findmnt which device holds /, and lsblk whether a crypt device is among its parents, which covers LUKS alone, LVM on LUKS and LUKS on LVM.

Without encryption, anyone who takes the laptop or the drive can read every file. The fix is only possible at reinstall, in the installer, so this is a WARN, not a FAIL.

ports

seccheck runs ss -Htlnp and lists every TCP port that listens on the network. Ports on 127.0.0.1 and ::1 only take connections from this machine, so it leaves them out. sshd is left out too, because the ssh check covers it.

Each port shows the address, the program and its pid. As a normal user, ss cannot see the owner of a port started by another user, so that line says owner hidden, root can see it.

Any such port is a WARN. The fix is to bind the program to 127.0.0.1 in its own config, or to stop it with port NUMBER --kill. A web server meant for the network is fine, and the WARN is the reminder that it is open.

sudo

Every sudo rule should ask for a password. A NOPASSWD rule lets anything that runs as your user become root at once, including a malicious script or a browser exploit. seccheck reads /etc/sudoers and every file in /etc/sudoers.d, and fails on the first NOPASSWD or !authenticate it finds. It also fails when a sudoers file is writable by anyone but root.

The fix is sudo visudo -f FILE, which checks the syntax before it saves. Never edit sudoers with a plain editor, because one typo locks you out of sudo.

sshdir

~/.ssh should be mode 700 and each private key 600.

seccheck finds private keys by their first line, which contains PRIVATE KEY. It reads only that line, never the key.

screenlock

The screen should lock on its own when you walk away. seccheck reads the desktop's settings.

DesktopWhere it reads
GNOME, Budgie, Pantheon, Unityorg.gnome.desktop.screensaver lock-enabled and org.gnome.desktop.session idle-delay, through gsettings
Cinnamonthe org.cinnamon.desktop keys of the same names
MATEorg.mate.screensaver
KDE PlasmaAutolock and Timeout in kscreenlockerrc, through kreadconfig5 or kreadconfig6

A lock that is off, or a screen that never goes idle, is a WARN. So is an idle time over 15 minutes. With no known desktop, such as on a server or over ssh, the check says SKIP.

path

No folder in PATH may be writable by others, because anyone could put a program there named ls or sudo. An empty entry or . in PATH is a WARN, because then a command in the current folder runs before the real one.

etc

No file in /etc may be writable by others. seccheck runs find /etc -xdev -type f -perm -0002 and fails on the first file it finds. Such a file is almost always a mistake from a chmod 777.

Options

OptionWhat it does
--only CHECKSRun only these checks, comma separated, such as ssh,ports. The names are in the table above. selinux and apparmor run mac. secure-boot, ssh-dir and screen-lock work too.
--strictExit 1 on a WARN as well as on a FAIL.
--listList the checks and what each one reads, and run none.
-q, --quietShow only the summary line.
-v, --verboseShow each check as it starts, and each command before it runs.
-h, --helpShow the help.

Per-distro notes

Needs

Nothing is required. Each check uses the tool it needs when it is present and says SKIP when it is not.

Examples

A desktop virtual machine

seccheck
WARN  firewall      no firewall is running
      fix  sudo apt install ufw, then
           sudo ufw enable
PASS  apparmor      enabled
FAIL  updates       60 security updates pending
      fix  pkg upgrade
PASS  ssh           sshd is not running
SKIP  secure boot   this machine boots with BIOS, not UEFI
WARN  encryption    / is not on LUKS
      fix  only at reinstall, turn on disk encryption
           in the installer
WARN  open ports    8820/tcp on 0.0.0.0, python pid 390057
                    8870/tcp on 0.0.0.0, python pid 969585
                    8894/tcp on 0.0.0.0, python3 pid 1750199
                    8840/tcp on 0.0.0.0, python3 pid 649883
      fix  bind them to 127.0.0.1, or stop them: port 8820 --kill
SKIP  sudo          needs root to read /etc/sudoers
PASS  ~/.ssh        no ~/.ssh folder
WARN  screen lock   the screen never goes idle, so it never locks
      fix  set a blank screen delay in the desktop settings
PASS  PATH          no world-writable folders
PASS  /etc files    no world-writable files
12 checks: 5 pass, 4 warn, 1 fail, 2 skipped (1 need root)
To run them too: sudo seccheck
echo $?
1

The 60 security updates are the one FAIL. Four development web servers listen on every address, which the ports check points out.

A cloud server with a risky sshd and sudo setup

sudo seccheck --only ssh,sudo
WARN  ssh password  sshd is running and takes passwords
      fix  add "PasswordAuthentication no" to
           /etc/ssh/sshd_config.d/00-local.conf, then
           svc restart ssh
FAIL  ssh root      PermitRootLogin yes, root can log in with a password
      fix  add "PermitRootLogin prohibit-password" to
           /etc/ssh/sshd_config.d/00-local.conf, then
           svc restart ssh
FAIL  sudo          NOPASSWD for %wheel in /etc/sudoers.d/90-wheel
      fix  sudo visudo -f /etc/sudoers.d/90-wheel, drop NOPASSWD
3 checks: 0 pass, 1 warn, 2 fail

PermitRootLogin yes came from 50-cloud-init.conf. The fix goes in 00-local.conf so sshd reads it first.

Just the ssh folder and PATH

seccheck --only sshdir,path
WARN  ~/.ssh        folder 755, others can list it
      fix  chmod 700 /home/khadir/.ssh
PASS  PATH          no world-writable folders
2 checks: 1 pass, 1 warn, 0 fail

See what a check runs

seccheck -v --only ports
seccheck: checking ports
+ ss -Htlnp
WARN  open ports    3000/tcp on 0.0.0.0, node pid 8120
                    8080/tcp on *, owner hidden, root can see it
      fix  bind them to 127.0.0.1, or stop them: port 3000 --kill
1 check: 0 pass, 1 warn, 0 fail

Port 8080 belongs to another user, so a normal user cannot see its owner.

A one-line result for a script

seccheck -q; echo $?
12 checks: 5 pass, 4 warn, 1 fail, 2 skipped (1 need root)
1
seccheck -q --only ssh,path --strict; echo $?
2 checks: 2 pass, 0 warn, 0 fail
0

The list of checks

seccheck --list
firewall    firewalld, ufw or nftables is on, and lets in little
mac         SELinux is enforcing or AppArmor is on
updates     no security updates wait, from the package lists on disk
ssh         sshd takes no passwords and no root password logins
secureboot  secure boot is on, on a UEFI machine
encryption  / sits on a LUKS encrypted device
ports       no TCP port listens on the network, other than sshd
sudo        every sudo rule asks for a password, needs root to read
sshdir      ~/.ssh is 700 and private keys are 600
screenlock  the desktop locks the screen when idle
path        no folder in PATH is world-writable, and . is not in it
etc         no file in /etc is world-writable

Troubleshooting

seccheck: no check named X The name is not in the list. Run seccheck --list for the names.

The ssh check says SKIP, needs root. One of the sshd config files is readable by root only, which is common for files that cloud-init writes. Run sudo seccheck --only ssh.

The updates check passes, but I know updates are out. The package lists on disk are old. Refresh them with sudo apt update, sudo dnf check-update or sudo zypper refresh, then run the check again.

A port I need shows as open. That is the point of the WARN. If the service is meant for the network, keep it, and make sure the firewall only lets in the addresses that should reach it.

The screen lock check says SKIP over ssh. It needs the desktop session's settings, which an ssh session cannot see. Run it in a terminal on the desktop.

I fixed PasswordAuthentication, but it still warns. An earlier file sets it to yes, and sshd keeps the first value. Put your line in 00-local.conf as the fix says, and check with sudo sshd -T | grep -i password.

Exit status

CodeMeaning
0No check failed. With --strict, no check failed or warned.
1A check failed. With --strict, a check failed or warned.
2Bad usage, such as an unknown check name or a word that is not an option.

SKIP never changes the exit status.

See also

port, svc, pkg, fixperms, sshd_config(5), sudoers(5), ss(8)