← All rules
SOCLE-CLD-FSP-159// File permissionsmediumpersistent config

Verify Permissions on SSH Server Config File

Ensures the /etc/ssh/sshd_config.d drop-in directory is owned by root with no access for group or other, so SSH policy fragments cannot be injected or read by unprivileged users.

Checked against the content of a persistent configuration file, the source of truth that survives reboots.

A pass proves? running now✓ on disk✓ survives rebootthe qualified verdict →
FedoraRHEL 10 / Rocky 10 / AlmaLinux 10RHEL 9 / Rocky 9 / AlmaLinux 9CIS 2.0.0Ubuntu 22.04CIS 3.0.0Ubuntu 24.04CIS 1.0.0Ubuntu 26.04
One check, maps to 2 standards

A mapping is a cross-reference to where each standard places this requirement, anchored and cross-validated, not a claim of equivalence. A passing check is evidence toward these references, how to read it.

Why this rule matters

On Ubuntu and RHEL 9 / Fedora the main sshd_config includes every fragment under /etc/ssh/sshd_config.d, so these drop-ins define the effective SSH policy (e.g. Ubuntu's 50-cloud-init.conf). If the directory is writable by group or other, a non-privileged user can add a fragment that re-enables root login, weakens ciphers or installs a backdoor on the next reload; if readable beyond root, the policy is disclosed. The directory must be owned by root with no read/write/execute for group or other and no special bits.

What Pavois checks

Pavois reads the effective directory mode of /etc/ssh/sshd_config.d and asserts no read/write/execute for group or other and no setuid/setgid/sticky bits. Guarded by only_if { file('/etc/ssh/sshd_config.d').exist? }. This is precisely the Pavois angle: a file-based scanner that only checks sshd_config misses the Included drop-ins that actually set the policy, securing this directory closes the injection path, and sshd -T confirms the resolved result.

only_if { file('/etc/ssh/sshd_config.d').exist? }
describe file('/etc/ssh/sshd_config.d') do
  it { should_not be_executable.by('owner') }
  it { should_not be_setuid }
  it { should_not be_executable.by('group') }
  it { should_not be_writable.by('group') }
  it { should_not be_readable.by('group') }
  it { should_not be_setgid }
  it { should_not be_executable.by('other') }
  it { should_not be_writable.by('other') }
  it { should_not be_readable.by('other') }
  it { should_not be_sticky }
end

How to verify it is applied

Run stat -c '%a %U %G' /etc/ssh/sshd_config.d. The expected output is 700 root root (or stricter): no read, write or execute for group or other. Then sshd -T shows the effective policy assembled from the fragments.

Inspect & investigate

stat /etc/ssh/sshd_config.d shows the directory mode; sshd -T shows the effective policy after assembling the drop-ins. SSH/auth events are in journalctl -u ssh / /var/log/auth.log (Ubuntu) or journalctl -u sshd / /var/log/secure (RHEL/Fedora). Directory changes appear in /var/log/audit/audit.log if watched.

Remediation

No automated harden plan is defined for this rule yet, so apply it manually: chown root:root /etc/ssh/sshd_config.d then chmod 0700 /etc/ssh/sshd_config.d.

Pavois applies this with its own harden engine, the plan below, not a shell script:

mode0600
path/etc/ssh/sshd_config.d
resourcefile
pavois harden plan local

where the target is local, a user@host SSH alias, or a container , Docs

Impact & precautions

Because drop-ins override the main config, a group- or world-writable sshd_config.d is an even sharper risk than a writable sshd_config: an unprivileged user can silently win the last-wins precedence and re-enable root login or weak auth on the next reload. Precautions: changing only directory permissions does not drop active sessions, so it is safe; keep it 0700 root:root, and validate any config change with sshd -t before reloading to avoid a daemon that fails to start and locks you out.

Standards mapping

StandardReferenceTypeVersionConfidence
CIS5.1.1directper OS, see the benchmark tablehigh
NISTAC-17(a), AC-6(1), CM-6(a)supporting800-53 Rev 5 · 800-171 Rev 2 (pinned)medium

Each reference is a cross-reference anchored in the upstream benchmark and cross-validated against the SCAP Security Guide and ansible-lockdown, not a claim of equivalence. Direct = a prescriptive, line-level requirement; supporting = an abstract control family (NIST) the check provides evidence toward. How to read a mapping.

Sources & references