Netwarden
Back to Documentation
Featuresv1.0

Security Findings Reference

Reference guide to every security finding Netwarden produces, how it is detected, what it means, and how to clear it.

Last updated: May 14, 2026
14 min read

Security Findings Reference

Netwarden continuously evaluates each monitored host for posture issues and emits a discrete security finding every time it observes something worth your attention. This page is the reference for what those findings are, how they are produced, how they route to alerts, and how they auto-resolve.

If you want the marketing-level overview of why this exists, see /features/security. If you want a hands-on tour of building alerts on top of these findings, see /blog/alerts-that-actually-page-you. This page is the precise reference: every finding type by its actual identifier, its trigger condition, and its default severity.

What security findings are

A finding is a discrete, deduplicated observation about a host. It has:

  • A finding type — a stable string identifier, e.g. ssh_root_login_enabled or cve_match.
  • A severitycritical, high, medium, low, or info.
  • A title and description describing what was observed.
  • A details payload with the supporting evidence (the offending sshd setting, the CVE ID, the listening port, etc).
  • A fingerprint — a stable hash of the host plus the finding type plus the parts of the observation that make it "the same finding next time". Two snapshots with the same fingerprint update one row; bursts of identical observations do not duplicate.
  • A status — open, acknowledged, or resolved.

Because every finding is tied to a stable fingerprint, your inbox does not fill with the same alert every minute. The same misconfigured sshd_config produces one finding that stays open until the configuration changes; the same vulnerable package produces one finding that stays open until the package is upgraded.

How findings are produced

Findings come from two places.

┌─────────────────────────────────────────────────────────────────┐
│  Agent on host                                                  │
│    snapshot collectors:                                         │
│      ssh_config           sshd_config + advertised crypto       │
│      listening_ports      ss/netstat output                     │
│      installed_packages   dpkg / rpm                            │
│      failed_login_geo     auth log + GeoIP enrichment           │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼  (agent uploads snapshots)
┌─────────────────────────────────────────────────────────────────┐
│  Platform: snapshot evaluators                                  │
│    pure functions: snapshot in → findings out                   │
│    upsert by fingerprint                                        │
│    auto-resolve fingerprints that stop appearing                │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│  Platform: server-side scrapers (no agent involvement)          │
│    CVE matcher (daily): join packages × Ubuntu/Debian/Red Hat   │
│    TLS cert scraper (daily): pull certs for tracked endpoints   │
│      both upsert into the same findings table                   │
└─────────────────────────────────────────────────────────────────┘

The agent owns the data closest to the host (config files, sockets, package versions, auth log). The platform owns the data closest to the world (CVE feeds, certificates). Both write to the same findings table using the same fingerprint convention.

Severity levels

Severity drives alert routing and dashboard prominence. The five levels are deliberately blunt — anything more granular would not change the action you take.

| Severity | Routing | What it means in practice | |---|---|---| | critical | Email + push + webhooks; surfaces at the top of the dashboard | Active exploitable issue. Treat as paging-worthy. | | high | Email + push + webhooks; prominent on the dashboard | Serious posture problem. Fix this week. | | medium | Email; appears in normal lists | Worth attention. Bundle into a maintenance window. | | low | Weekly digest only | Hygiene item. Bundle into the next quarterly review. | | info | Dashboard only, no notification | Diagnostic context, not actionable on its own. |

Per-tenant routing rules can downgrade or upgrade these defaults; see How alerts route below.

The 14 finding types

Fourteen finding types today, grouped into six families. Each entry uses the exact identifier the platform writes (so you can match on it in webhooks and queries) and lists the trigger, default severity, and resolution behavior.

SSH posture (5)

These come from the ssh_config snapshot. The agent parses sshd_config, applies Match blocks, and reports the effective settings.

ssh_root_login_enabled

  • Trigger: PermitRootLogin yes is in effect.
  • Default severity: high.
  • Why it matters: Direct root login over SSH is a high-value target for credential stuffing and brute force, and it eliminates per-user attribution in audit logs. Disable in favour of a non-root user with sudo.
  • Auto-resolves when: the next ssh_config snapshot reports PermitRootLogin no (or prohibit-password if you only allow root with keys).

ssh_password_auth_enabled

  • Trigger: PasswordAuthentication yes is in effect.
  • Default severity: medium.
  • Why it matters: Password-based SSH is the dominant vector for credential-stuffing attacks. Public-key authentication eliminates the entire class.
  • Auto-resolves when: the next snapshot reports PasswordAuthentication no.

ssh_protocol_v1_enabled

  • Trigger: the Protocol directive includes 1.
  • Default severity: critical.
  • Why it matters: SSHv1 has known cryptographic weaknesses and was deprecated decades ago. Modern OpenSSH builds drop the option entirely; if you see this finding, you are running a legacy fork.
  • Auto-resolves when: the Protocol directive is removed or set to 2 only.

ssh_empty_passwords_allowed

  • Trigger: PermitEmptyPasswords yes is in effect.
  • Default severity: critical.
  • Why it matters: Any account on the host with a blank password is reachable directly over SSH. This combines catastrophically with ssh_password_auth_enabled.
  • Auto-resolves when: the next snapshot reports PermitEmptyPasswords no.

ssh_x11_forwarding_enabled

  • Trigger: X11Forwarding yes is in effect.
  • Default severity: low.
  • Why it matters: X11 forwarding is rarely needed on servers and broadens the SSH attack surface. Disable unless you actively run GUI applications over SSH.
  • Auto-resolves when: the next snapshot reports X11Forwarding no.

SSH crypto (3)

These come from the same ssh_config snapshot but evaluate the algorithms sshd advertises. At most one finding fires per category — the platform aggregates the offenders into a single row whose fingerprint includes the sorted offender list, so the finding mutates if you remove one bad algorithm and add another.

ssh_weak_kex

  • Trigger: any algorithm in KexAlgorithms matches the hardcoded weak list (diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, diffie-hellman-group-exchange-sha1) or ends in -sha1.
  • Default severity: high.
  • Why it matters: SHA-1 KEX variants and small Diffie-Hellman primes are broken in the cryptographic sense — exposed to downgrade and offline collision attacks.

ssh_weak_cipher

  • Trigger: any algorithm in Ciphers matches the weak list (CBC-mode AES, 3DES, Blowfish, CAST, all RC4 variants).
  • Default severity: high.
  • Why it matters: CBC mode is exposed to BEAST/POODLE-class issues; RC4 is broken outright.

ssh_weak_mac

  • Trigger: any algorithm in MACs matches the weak list (hmac-md5, hmac-md5-96, hmac-sha1-96, [email protected], anything containing md5, or hmac-sha1).
  • Default severity: medium when an MD5 or 64-bit-truncated MAC is present; low when only hmac-sha1 is present (a deprecated-but-still-widely-deployed legacy nudge).
  • Why it matters: MD5 forgery is computationally cheap; 64-bit MACs have insufficient collision resistance.

Network exposure (2)

These come from the listening_ports snapshot. The agent enumerates listening sockets, their bind addresses, and the owning process.

public_management_port

  • Trigger: a socket is bound to a non-loopback address (i.e. 0.0.0.0, ::, or a specific public interface) on a port from the management list (SSH 22, Postgres 5432, MySQL 3306, MongoDB 27017, Redis 6379, Memcached 11211, Elasticsearch 9200, Docker 2375/2376, Kubernetes API 6443, Telnet 23, RDP 3389, VNC 5900, etc).
  • Default severity: high.
  • Why it matters: Management surfaces should never be reachable from the public internet. Bind to localhost or restrict by firewall.
  • Note: one finding fires per (port, proto) pair so you can resolve them independently. PID and process name are intentionally excluded from the fingerprint, so a service restart does not duplicate the finding.

many_public_bindings

  • Trigger: the host has more than five more public-bind sockets than loopback-bind sockets.
  • Default severity: info.
  • Why it matters: A high public-to-loopback ratio is unusual for a server and worth reviewing. The default is informational because legitimate cases exist (an edge host with a dozen exposed services); use it as a prompt to audit, not a page.

Vulnerabilities (1)

cve_match

  • Trigger: the daily CVE matcher joins each host's installed_packages snapshot against cve_affected_packages and emits a finding when the installed version is older than the fixed version listed in an advisory.
  • Default severity: routed by CVSS v3, NVD's published rating ranges:
    • 9.0 – 10.0 → critical
    • 7.0 – 8.9 → high
    • 4.0 – 6.9 → medium
    • 0.1 – 3.9 → low
    • When CVSS is unavailable, fall back to the upstream feed's published severity (Red Hat usually has one). When neither is available, fall back to medium rather than guessing.
  • Sources:
    • Ubuntu USN feed (ubuntu.com/security/notices.json)
    • Debian DSA tracker
    • Red Hat OVAL (RHEL 7/8/9 — also covers Rocky, Alma, CentOS Stream)
    • NVD for CVSS enrichment
  • Auto-resolves when: the next package snapshot reports a fixed version and the matcher's re-run no longer emits the fingerprint.
  • Note: one finding per (advisory_id, package_name) per host. A single Ubuntu USN that fixes three packages produces three findings on a host that has all three installed.

Identity (2)

These come from the failed_login_geo snapshot. The agent tails the auth log for failed SSH attempts every 60 seconds, groups by source IP, and the platform enriches with country data via MaxMind GeoLite2.

failed_login_high_risk_country

  • Trigger: at least 20 failed login attempts in the 60-second window from a country on the high-risk list (RU, CN, KP, IR, BY).
  • Default severity: high.
  • Why it matters: These countries disproportionately appear as the source of SSH brute-force and credential-stuffing campaigns in real-world honeypot data. The list is deliberately conservative — hosts with legitimate users in those regions will see false positives, which auto-resolve as soon as the burst ends.
  • Fingerprint: one finding per (host, country) — bursts from the same country dedupe.

failed_login_country_anomaly

  • Trigger: at least 5 failed login attempts from a country the host has not seen in failed-login traffic in the prior 30 days, AND the country is not already covered by a high-risk-country finding.
  • Default severity: medium.
  • Why it matters: Any sustained traffic from a brand-new origin is worth a second look. New contractor, relocated employee, VPN egress change — or genuine adversarial reconnaissance. Confirm with your team before assuming the worst.
  • Auto-resolves when: the next 60-second window does not reproduce the fingerprint.

Both identity findings require GEOLITE2_CITY_PATH to be set on the platform (see the Self-Hosting guide for setup). Without GeoIP enrichment, country fields are null and these findings cannot fire.

Certificates (1)

ssl_cert_expiring_soon

  • Trigger: the daily TLS scraper observes a tracked endpoint whose certificate expires within a configurable window (default 30 days).
  • Default severity: medium outside 14 days, high inside 14, critical inside 7.
  • Why it matters: Expired certificates break clients and trigger browser warnings.
  • Auto-resolves when: the next scrape sees a renewed certificate whose notAfter is back outside the window.

How alerts route

A finding being created and an alert being delivered are separate things. The notification gate considers severity, per-channel preferences (Settings → Notifications → Security alerts), maintenance / quiet-hour suppression, and recent acknowledgement state. A finding that was acknowledged in the last hour does not re-page; the dashboard still surfaces it.

For the high-volume operator's pattern — webhook everything to your own router and build escalation policy in PagerDuty / Opsgenie / a homegrown tool — see /blog/alerts-that-actually-page-you.

Auto-resolve behavior

Every snapshot type carries a coverage list of the finding types it produces. When an ingest cycle completes, the platform compares the fingerprints it just emitted to the open findings of those types for the same host; anything no longer present is closed with a system resolution flag.

For example: a host with PermitRootLogin yes for weeks gets fixed. The next ssh_config snapshot lands without that fingerprint, and the open ssh_root_login_enabled finding flips to resolved with the timestamp attached.

cve_match is intentionally excluded from this snapshot-driven path — CVE findings are produced by a separate cron and are resolved by the matcher's own re-emission pass.

Acknowledging vs resolving

  • Acknowledge — "I see this, I'm working on it." Stays in the active list with an acknowledged badge; stops re-notifications. Use during incident triage.
  • Resolve (manual) — "I have fixed this." Moves out of the active list immediately. The next snapshot re-opens it if the underlying condition is still present.

Most of the time, let the auto-resolver close findings — the close timestamp then matches the moment the underlying condition actually changed.

Configuring per-tenant alert routing

Routing lives in Settings → Notifications → Security alerts, which renders a severity-by-channel matrix:

| | Email | Push | Webhook | |---|---|---|---| | Critical | on | on | on | | High | on | on | optional | | Medium | digest | off | optional | | Low | digest | off | off | | Info | off | off | off |

Common adjustments: turn webhook on for medium and low if you want everything in your own incident system; turn email on for low if you want a real-time stream rather than a digest. Per-host overrides are not yet available — preferences are tenant-wide. Per-host routing is on the roadmap.

Time-to-resolution

The Security overview dashboard shows a TTR widget — the median hours between a finding being opened and resolved, computed over the last 30 days and faceted by severity. It is intentionally a single number rather than a chart: a posture-improvement metric for postmortems and quarterly reviews, not a real-time gauge.

Caveats: only resolved findings count (open ones do not pull the median down); auto-resolved and manually-resolved are pooled; findings resolved within 60 seconds of opening are excluded so transient bursts do not bias the median toward zero. Use TTR as a directional signal — a trend up over weeks usually means a fleet-wide issue is going unaddressed.

What's NOT covered

Be honest about scope:

  • Not a full vulnerability scanner. We match installed packages against published advisories. We do not run authenticated config scans, do not parse application configs (nginx, Apache, web frameworks), and do not crawl your runtime for misconfigured permissions.
  • Not an EDR. No process behaviour analytics, no kernel hooks, no malware detection, no file integrity monitoring beyond what you can build yourself with custom alerts on top of the metrics pipeline.
  • Not a SIEM. No log search, no correlation across thousands of events, no compliance dashboards. Failed-login enrichment is the only "log signal" we ingest, and it is bounded to a narrow purpose.
  • No GeoIP without your MaxMind file. The two identity findings depend on customer-supplied GeoLite2 data. Without it, country fields are null and those findings do not fire. See Self-Hosting → GeoIP setup for how to wire it up.
  • No SUSE / Arch / Gentoo / Alpine CVE feeds. Ubuntu, Debian, and the Red Hat family are the only distributions covered today. The other thirteen finding types still work on those distributions; only cve_match is unavailable.

If something on this list is a hard requirement for your environment and you would like our roadmap perspective on when it might land, get in touch.

Was this page helpful?

Help us improve our documentation

Edit on GitHubReport an Issue