No compiler available (attack surface)
Ensures no C/C++ compiler (gcc, cc, clang, g++, tcc) is present on a production host, reducing the attack surface available to an intruder.
Checked against what is installed or registered, packages present/absent, account databases.
Why this rule matters
A compiler on a production server is a gift to an attacker: it lets them build privilege-escalation exploits, kernel modules, rootkits or custom tooling directly on the target, turning source they smuggle in into working binaries that evade allow-lists. Production hosts almost never need to compile code locally, software should be built elsewhere and deployed as packages. Removing compilers forces an attacker to bring pre-built tools, which is noisier and easier to block.
What Pavois checks
Pavois checks the effective state by probing PATH (command -v) for each known compiler binary and expects an empty result. Resolving the live PATH is more reliable than scanning a package manifest: it catches a compiler installed by hand, symlinked, or shipped inside another package.
describe command('for c in gcc cc c++ g++ cpp make; do p=$(command -v $c 2>/dev/null) || continue; p=$(readlink -f \"$p\"); find \"$p\" -perm -o+x 2>/dev/null; done') do
its('stdout.strip') { should eq '' }
endHow to verify it is applied
Run for c in gcc cc clang g++ tcc; do command -v $c; done, it should print nothing. Each missing binary confirms no compiler is reachable on PATH.
Inspect & investigate
There is no runtime log for this rule. Confirm absence with command -v gcc cc clang g++ tcc (empty) and dpkg -l gcc 'g++' clang / rpm -q gcc to verify the packages are not installed.
Remediation
No automated remediation is shipped, so apply it manually: remove the compiler packages (apt purge gcc g++ clang / dnf remove gcc gcc-c++ clang) and any standalone compiler binaries. Restrict execute permissions on any compiler that must stay (e.g. for DKMS) to root only.
Pavois applies this with its own harden engine, the plan below, not a shell script:
| command | for p in gcc cpp g++ gcc-12 g++-12 cpp-12 clang tcc tcc-dev; do dpkg -l "$p" 2>/dev/null | grep -q '^ii' && DEBIAN_FRONTEND=noninteractive apt-get purge -y "$p" >/dev/null 2>&1; done; true; for c in gcc cc c++ g++ cpp make; do p=$(command -v $c 2>/dev/null) || continue; chmod o-x "$p" 2>/dev/null; don; for c in gcc cc c++ g++ cpp make; do p=$(command -v $c 2>/dev/null) || continue; chmod o-x "$(readlink -f "$p")" 2>/dev/null; done; true |
|---|---|
| name | purge-compilers |
| not_if | test -z "$(for c in gcc cc c++ g++ cpp make; do p=$(command -v $c 2>/dev/null) || continue; p=$(readlink -f \"$p\"); find \"$p\" -perm -o+x 2>/dev/null; done)" |
| resource | exec |
pavois harden plan localwhere the target is local, a user@host SSH alias, or a container , Docs
Impact & precautions
Removing compilers can break builds and tooling that compile at install/runtime: DKMS kernel modules, make-based installers, some language package managers (native gems/wheels/npm addons), and configuration management that builds from source. Before applying, verify the host does not rely on these, if it does, either keep the compiler with restricted permissions or move that build step to a dedicated build server. Pure runtime/production servers are safe.