# yaml-language-server: $schema=../../../../schema/control.schema.json id: CB-DEB-NET-017 title: Limit SSH connections and close dead sessions finding: title: The SSH server keeps dead sessions open and accepts many concurrent unauthenticated connections description: Unbounded connection and session counts let a single client exhaust the SSH server, and dead sessions stay open for anyone who takes over the network path. status: active profiles: [core] risk: severity: low assessment: automated tags: [ssh, session, denial-of-service] applicability: facts: [openssh-server] description: | These OpenSSH server options limit resources used per client and detect dead connections: - `ClientAliveInterval` (1 to {{ ssh_client_alive_interval }} seconds) and `ClientAliveCountMax` (1 to {{ ssh_client_alive_count_max }}): the server checks that the client still answers, and closes the session after `ClientAliveCountMax` unanswered checks; - `MaxStartups` at most `10:30:60`: beyond 10 unauthenticated connections, new ones are refused with a probability of 30 %, rising to 100 % at 60; - `MaxSessions` at most {{ ssh_max_sessions }}: shells, commands and subsystems multiplexed on one connection. rationale: | Sessions whose client has gone away (laptop closed, network cut) keep a shell open on the server; closing them limits what a later session hijack can reach. Connection limits keep a brute force tool or a flood of half-open connections from making the server unreachable for administrators. impact: | Sessions of clients that stop answering for more than {{ ssh_client_alive_interval }} × {{ ssh_client_alive_count_max }} seconds are closed. Automation that opens many parallel connections or multiplexed sessions (Ansible pipelining, `ControlMaster`) may hit the limits; raise them through tailoring if needed. notes: | OpenSSH's own default for `ClientAliveInterval` is `0` (no check); the Debian cloud images set `120`. Idle shell sessions are closed by `TMOUT` (CB-DEB-AUTH-020), not by these options, since a live client always answers keepalive checks. The fix only changes the options that are out of bounds, in `/etc/ssh/sshd_config.d/00-cirsec.conf`. setting: location: /etc/ssh/sshd_config.d/00-cirsec.conf default_value: ClientAliveInterval 0 (120 on cloud images), ClientAliveCountMax 3, MaxStartups 10:30:100, MaxSessions 10 recommended_value: "ClientAliveInterval 1-{{ ssh_client_alive_interval }}, ClientAliveCountMax 1-{{ ssh_client_alive_count_max }}, MaxStartups <= 10:30:60, MaxSessions <= {{ ssh_max_sessions }}" parameters: - name: ssh_client_alive_interval type: integer description: Maximum interval between two keepalive checks of the client. unit: seconds default: 300 minimum: 1 maximum: 900 - name: ssh_client_alive_count_max type: integer description: Maximum number of unanswered keepalive checks before the session is closed. default: 3 minimum: 1 maximum: 10 - name: ssh_max_sessions type: integer description: Maximum sessions per SSH connection. default: 10 minimum: 1 maximum: 10 audit: manual: | Run `sshd -T | grep -E '^(clientaliveinterval|clientalivecountmax|maxstartups|maxsessions) '`. `clientaliveinterval` must be between 1 and {{ ssh_client_alive_interval }}, `clientalivecountmax` between 1 and {{ ssh_client_alive_count_max }}, each field of `maxstartups` at most `10:30:60`, and `maxsessions` at most {{ ssh_max_sessions }}. checks: - id: client-alive-interval-set engine: sshd-config description: ClientAliveInterval is not 0 (keepalive off). spec: { key: clientaliveinterval, operator: ">=", value: 1 } - id: client-alive-interval engine: sshd-config description: ClientAliveInterval upper bound. spec: { key: clientaliveinterval, operator: "<=", value: "{{ ssh_client_alive_interval }}" } - id: client-alive-count-set engine: sshd-config description: ClientAliveCountMax is not 0. spec: { key: clientalivecountmax, operator: ">=", value: 1 } - id: client-alive-count engine: sshd-config description: ClientAliveCountMax upper bound. spec: { key: clientalivecountmax, operator: "<=", value: "{{ ssh_client_alive_count_max }}" } - id: max-startups engine: sshd-config description: MaxStartups at most 10:30:60. spec: key: maxstartups operator: match value: '^([1-9]|10):([1-9]|[12][0-9]|30):([1-9]|[1-5][0-9]|60)$' - id: max-sessions engine: sshd-config description: MaxSessions upper bound. spec: { key: maxsessions, operator: "<=", value: "{{ ssh_max_sessions }}" } remediation: manual: | Add to `/etc/ssh/sshd_config.d/00-cirsec.conf`: ``` ClientAliveInterval {{ ssh_client_alive_interval }} ClientAliveCountMax {{ ssh_client_alive_count_max }} MaxStartups 10:30:60 MaxSessions {{ ssh_max_sessions }} ``` Check with `sshd -t`, then run `systemctl reload ssh`. effects: restart: service services: [ssh] disruption: low lockout_risk: true rollback: | Remove the lines from `/etc/ssh/sshd_config.d/00-cirsec.conf` and run `systemctl reload ssh`. scripts: - id: limits engine: shell file: fix.sh references: - title: sshd_config(5), Debian manual pages url: https://manpages.debian.org/trixie/openssh-server/sshd_config.5.en.html publisher: Debian kind: vendor-doc accessed: 2026-10-18 - title: NIST IR 7966 - Security of Interactive and Automated Access Management Using Secure Shell (SSH) url: https://csrc.nist.gov/pubs/ir/7966/final publisher: NIST kind: guide accessed: 2026-10-18 mappings: - framework: nist-800-53r5 framework_version: "5.1.1" id: SC-10 relation: partial - framework: nist-800-53r5 framework_version: "5.1.1" id: SC-5 relation: related - framework: cis-debian-12 framework_version: "2.0.0" id: "5.1.7" relation: equivalent - framework: cis-debian-12 framework_version: "2.0.0" id: "5.1.17" relation: equivalent - framework: cis-debian-12 framework_version: "2.0.0" id: "5.1.18" relation: equivalent - framework: cis-debian-13 framework_version: "1.1.0" id: "5.1.8" relation: equivalent - framework: cis-debian-13 framework_version: "1.1.0" id: "5.1.19" relation: equivalent - framework: cis-debian-13 framework_version: "1.1.0" id: "5.1.20" relation: equivalent threats: - framework: mitre-attack id: T1499 - framework: cwe id: CWE-400 related_controls: - id: CB-DEB-AUTH-020 type: related authors: - name: Alice github: Sn0wAlice verified: - date: 2026-10-18 by: Sn0wAlice versions: ["12"] environment: Proxmox VM 921, Debian 12 genericcloud image, kernel 6.1.0-54-cloud-amd64 notes: "fix.sh sets MaxStartups 10:30:60 on stock config, and interval/count when set to 0; SSH by key still accepted." - date: 2026-10-18 by: Sn0wAlice versions: ["13"] environment: Proxmox VM 931, Debian 13 genericcloud image, kernel 6.12.113+deb13-cloud-amd64 notes: "fix.sh sets MaxStartups 10:30:60 on stock config, and interval/count when set to 0; SSH by key still accepted." introduced_in: 0.1.0 created: 2026-10-18 updated: 2026-10-18