No description
  • Go 99.1%
  • Makefile 0.5%
  • Dockerfile 0.4%
Find a file
2026-04-30 08:46:17 +07:00
checker checker: build host FQDN from subdomain + apex at service scope 2026-04-30 08:46:08 +07:00
plugin Initial commit 2026-04-26 16:23:21 +07:00
.gitignore Initial commit 2026-04-26 16:23:21 +07:00
Dockerfile Initial commit 2026-04-26 16:23:21 +07:00
go.mod Initial commit 2026-04-26 16:23:21 +07:00
go.sum Initial commit 2026-04-26 16:23:21 +07:00
LICENSE Initial commit 2026-04-26 16:23:21 +07:00
main.go Initial commit 2026-04-26 16:23:21 +07:00
Makefile Initial commit 2026-04-26 16:23:21 +07:00
NOTICE Initial commit 2026-04-26 16:23:21 +07:00
README.md Include rules section 2026-04-30 08:46:17 +07:00

checker-ssh

Deep SSH security checker for happyDomain.

Given an abstract.Server service (A / AAAA / SSHFP records), the checker connects to the advertised SSH port(s) and produces a comprehensive audit: reachability, banner-to-CVE matches, full algorithm posture (KEX / host-key / cipher / MAC / compression), observed host keys, SSHFP fingerprint validation, and authentication method exposure.

What it checks

Reachability

  • TCP connect to port 22 (and optionally extra ports) on every A/AAAA address of the service.
  • SSH-2.0 protocol banner read.

Banner / CVE

The banner is parsed into an OpenSSH_X.Ypz tuple and matched against a bundled subset of the ssh-audit vulnerability database, including:

CVE Issue
CVE-2024-6387 regreSSHion - unauth RCE as root (8.5p1 <= v < 9.8p1)
CVE-2023-38408 ssh-agent PKCS#11 RCE (5.5 ≤ v < 9.3p2)
CVE-2023-48795 Terrapin prefix-truncation (v < 9.6p1)
CVE-2021-41617 AuthorizedKeysCommand privdrop (6.2 ≤ v < 8.8p1)
CVE-2020-15778 scp command injection (v < 8.4p1)
CVE-2018-15473 username enumeration (v < 7.8p1)

Algorithm posture

A raw SSH_MSG_KEXINIT is exchanged with the server to enumerate every algorithm it advertises. Each entry is graded against a curated table inspired by ssh-audit:

  • crit: diffie-hellman-group1-sha1 (Logjam), 3des-cbc (Sweet32), arcfour*, hmac-md5*, hmac-sha1-96, ssh-dss, none.
  • warn: ssh-rsa (RFC 8332 deprecated), diffie-hellman-group14-sha1, AES-CBC, non-ETM MACs, hmac-sha1, missing strict-KEX marker (CVE-2023-48795 mitigation).
  • ok: curve25519-sha256, sntrup761x25519-sha512@openssh.com, mlkem768x25519-sha256, ssh-ed25519, AES-GCM/ChaCha20-Poly1305, SHA-2 ETM MACs.

SSHFP validation

For each observed host key, the checker:

  • computes SHA-1 and SHA-256 fingerprints,
  • matches them against the abstract.Server.SSHFP records declared in the zone,
  • flags sshfp_missing, sshfp_not_covered, sshfp_only_sha1 or sshfp_mismatch as appropriate, with copy-pasteable fix snippets.

Authentication methods

A second connection is opened with a dummy user and no credentials. The server replies with the auth-method list, which is surfaced as password, publickey, keyboard-interactive chips. Password authentication triggers a password_auth_enabled warning.

HTML report

The iframe report is structured for "fix me fast":

  1. Overall status banner + SSHFP verdict chips.
  2. What to fix: top issues (crit -> warn), each with a copy-pasteable remediation snippet (sshd_config lines, SSHFP DNS records, ssh-keygen invocations).
  3. SSHFP table with per-record match status.
  4. Per-endpoint details: expandable sections with host-key fingerprints, algorithm tables (broken entries highlighted), and advertised auth methods.

Usage

Standalone HTTP server

make
./checker-ssh -listen :8080

Endpoints:

  • GET /health
  • GET /definition
  • POST /collect
  • POST /evaluate
  • POST /report

Docker

make docker
docker run -p 8080:8080 happydomain/checker-ssh

happyDomain plugin

make plugin
# produces checker-ssh.so, loadable as a Go plugin

Options

Option Type Default Description
ports string "" Comma-separated extra ports (port 22 is always probed).
probeTimeoutMs number 10000 Per-endpoint dial + handshake timeout.
includeAuthProbe bool true Open a second connection to enumerate auth methods.

Rules

Code Description Severity
ssh.tcp_reachable Verifies that every probed (address, port) pair accepts a TCP connection. CRITICAL
ssh.handshake Verifies that the SSH banner exchange and KEXINIT parse succeed on every reachable endpoint. CRITICAL
ssh.protocol_version Verifies every endpoint advertises SSH-2 and rejects the legacy SSH-1 protocol. CRITICAL
ssh.banner_software Flags servers whose banner is not a recognised OpenSSH build. INFO
ssh.known_vulnerabilities Matches the advertised OpenSSH version against a curated catalog of remotely-observable CVEs. CRITICAL
ssh.host_key_strength Flags SSH host keys whose size is below the currently accepted minimum (e.g. RSA < 2048 bits). CRITICAL
ssh.kex_algorithms Flags key-exchange algorithms advertised by the server that are weak or broken. CRITICAL
ssh.host_key_algorithms Flags server host-key algorithms that are weak or deprecated (ssh-rsa/SHA-1, ssh-dss, ...). CRITICAL
ssh.cipher_algorithms Flags symmetric ciphers advertised by the server that are weak or broken (CBC, 3DES, RC4, ...). CRITICAL
ssh.mac_algorithms Flags MAC algorithms advertised by the server that are weak (SHA-1, non-ETM, ...). CRITICAL
ssh.strict_kex Verifies the server advertises the strict-KEX marker (CVE-2023-48795 Terrapin mitigation). WARNING
ssh.preauth_compression Flags servers that offer pre-authentication zlib compression (prefer zlib@openssh.com). INFO
ssh.auth_methods Reviews the advertised authentication methods (password exposure, public-key availability). WARNING
ssh.sshfp_alignment Compares published SSHFP records against the observed host keys (match, missing, mismatch). CRITICAL
ssh.sshfp_hash Flags SSHFP record sets that only publish SHA-1 (type 1) fingerprints instead of SHA-256. WARNING

Observation key

Writes a single observation under ssh:

{
  "domain": "...",
  "endpoints": [
    {
      "host": "...", "port": 22, "address": "...",
      "banner": "SSH-2.0-OpenSSH_9.3p1",
      "kex_algorithms": ["curve25519-sha256", "..."],
      "host_keys": [{"type": "ssh-ed25519", "sha256": "abc..."}],
      "auth_methods": ["publickey"],
      "issues": [ { "code": "...", "severity": "warn", ... } ]
    }
  ],
  "sshfp": { "present": true, "records": [...] },
  "collected_at": "..."
}

License & licensing roadmap

This project is currently licensed under the GNU Affero General Public License v3.0 (see LICENSE), because it still imports happydns.ServiceMessage and abstract.Server from the happyDomain server module (git.happydns.org/happyDomain/model and git.happydns.org/happyDomain/services/abstract), which are themselves distributed under AGPL-3.0 and a commercial license.

The core checker types (CheckerOptions, CheckerDefinition, ObservationProvider, CheckRule, …) have already been migrated to checker-sdk-go; only the service-message types remain on the AGPL side.

Planned relicensing: as soon as the remaining ServiceMessage / abstract.Server dependency has been removed (moved into a dedicated permissively licensed module), this project will be relicensed under the MIT License, in line with the rest of the happyDomain checker ecosystem (see checker-dummy for the target shape).

Contributors notice: by submitting a contribution to this repository, you accept that your contribution will be relicensed from AGPL-3.0 to MIT at the time of the relicensing described above. If you do not agree with this, please do not submit contributions until the relicensing has taken place.

The third-party Apache-2.0 attributions for checker-sdk-go are recorded in NOTICE and must accompany any binary or source redistribution of this project.