← All rules
SOCLE-CLD-SSH-011// SSHloweffective runtime

Disable SSH TCPKeepAlive (use ClientAlive instead)

Turn off the TCP-level keepalive (TCPKeepAlive no) so that session liveness is decided only by the ClientAliveInterval / ClientAliveCountMax probes. TCP keepalives travel outside the encrypted channel and are spoofable: an attacker on the path can forge them to keep a dead or hijacked session registered as alive.

Checked against the resolved running state (e.g. sshd -T, sysctl, systemctl show), catches drop-ins and Includes a file read would miss. Caveat: runtime ≠ persistence; a value correct now may not survive a reboot.

A pass proves✓ running now✓ on disk✓ survives rebootthe qualified verdict →
Debian 12CIS 1.1.0Debian 13CIS 1.0.0FedoraRHEL 10 / Rocky 10 / AlmaLinux 10RHEL 8 / Rocky 8 / AlmaLinux 8CIS 4.0.0RHEL 9 / Rocky 9 / AlmaLinux 9CIS 2.0.0Ubuntu 24.04CIS 1.0.0Ubuntu 26.04

What Pavois checks

Pavois runs sshd -T and requires the resolved line tcpkeepalive no. sshd -T prints the daemon's effective configuration, after all Include directives and every drop-in in /etc/ssh/sshd_config.d/, so a later drop-in that restores the default yes is detected. A file-based check on /etc/ssh/sshd_config would miss it.

describe command('sshd -T') do
  its('stdout') { should match(/^tcpkeepalive\s+no$/i) }
end

How to verify it is applied

Run sshd -T | grep -iE '^(tcpkeepalive|clientalive)' as root. Expected output, tcpkeepalive off and the encrypted probes taking over:

tcpkeepalive no
clientaliveinterval 300
clientalivecountmax 3

The clientalive* values come from their own Pavois rules; what this rule requires is the first line.

Inspect & investigate

The directive itself produces no log entry. What becomes visible is the ClientAlive-driven teardown: when a client stops answering the encrypted probes, sshd logs in /var/log/auth.log (or journalctl -u ssh):

sshd[1234]: Timeout, client not responding from user alice 203.0.113.10 port 51234

With TCPKeepAlive yes and no ClientAlive probes, that same dead session would simply linger, silently.

Remediation

The Pavois harden plan uses the sshd_setting resource to set the directive tcpkeepalive to no in the Pavois drop-in under /etc/ssh/sshd_config.d/. The file is validated with sshd -t -f <file> before being kept, and a change notifies a reload of ssh.service.

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

directivetcpkeepalive
notifyaction: reload, service: ssh.service
resourcesshd_setting
valueno
verifysshd -t -f %{path}
pavois harden plan local

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

Impact & precautions

Disabling TCP keepalives removes the packets that keep NAT and stateful-firewall entries warm. If ClientAliveInterval is unset (or larger than the firewall's idle timeout), long idle sessions can be silently dropped by a middlebox: set ClientAliveInterval below that timeout, or have clients use ServerAliveInterval. Conversely, do not disable TCPKeepAlive and leave ClientAlive off: the server would then never detect a dead peer and would accumulate orphaned sessions. The change is applied by a reload, so current sessions are unaffected.

Sources & references