Someone figured out they can scribble a neighbor's address on their parking ticket and get the neighbor towed instead
CVE-2026-109786 is a log-injection flaw in fail2ban's sshd filter (config/filter.d/sshd.conf), affecting versions 0.10.5 through 1.1.1. The vulnerable regex patterns __suff and __on_port_opt both accepted an on \S+ suffix when parsing SSH authentication failure logs. Because OpenSSH logs the offered username verbatim, a remote unauthenticated attacker can attempt an SSH login with a crafted username like x VICTIM-IP on — fail2ban's regex then misattributes the failure to the victim's IP address instead of the attacker's. Repeat this enough times and fail2ban bans the *victim*, locking a legitimate admin or service out of SSH. The fix (commit ddd879d) strips the on \S+ clause entirely, restricting the suffix pattern to port \d+ and [preauth] only.
The vendor's MEDIUM 5.3 rating is honest and well-calibrated. The CVSS vector AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L correctly reflects that this is unauthenticated and network-reachable (the scary part) but caps the impact at Low availability with zero confidentiality or integrity exposure (the ceiling). There's no path from this bug to code execution, data exfiltration, or privilege escalation. The realistic worst case is targeted SSH lockout of specific IPs on specific hosts — disruptive during incident response, but not catastrophic. The vendor didn't under-rate this to avoid embarrassment; 5.3 is the right number.
4 steps from start to impact.
Identify a fail2ban-protected SSH target
sshd jail enabled. SSH on port 22 is trivially discoverable via Shodan, Censys, or basic port scanning. fail2ban is extremely common on internet-facing Linux hosts — it ships in every major distribution's repo and is the de facto SSH brute-force mitigation.- Target host exposes SSH (port 22 or custom) to the attacker's network
- fail2ban is running with the sshd jail active (default config)
- fail2ban version is 0.10.5–1.1.1 (unpatched)
- Hosts behind VPN/bastion architectures may not expose SSH directly to the internet
- Some deployments use custom filter files (
sshd.local) that may have different regex
Craft malicious SSH username
on, e.g. x 10.0.0.50 on or x 203.0.113.42 on. This is trivial — no tooling required, just standard SSH client syntax: ssh 'x 10.0.0.50 on'@target. The attacker must know or guess the IP address they want to ban.- Attacker knows the IP address of the legitimate user/admin they want to lock out
- Attacker must know or enumerate target victim IPs — random banning is less useful strategically
- Some environments use certificate-based auth and disable password auth, reducing log verbosity for invalid usernames
Send repeated crafted login attempts
Invalid user x 10.0.0.50 on from ATTACKER-IP port 54321. The vulnerable regex in fail2ban's sshd filter parses 10.0.0.50 as the source host and on as a valid suffix, misattributing the failure to the victim IP. The attacker needs to hit the maxretry threshold (default 5) before their own real IP accumulates enough bans.- The auth log format matches what the sshd filter expects (standard OpenSSH)
- maxretry threshold is reachable from the attacker's IP before the attacker themselves is banned
- The attacker's real IP may also accumulate failures and get banned first, depending on whether fail2ban double-matches the line
- Rate limiting at the network level (iptables recent module, connection rate limits) may slow the attacker below the threshold
- SSH connection throttling (
MaxStartupsin sshd_config) limits concurrent unauthenticated connections
Invalid user patterns with embedded IP addresses would catch this immediatelyVictim IP is banned by fail2ban
maxretry threshold is reached for the misattributed victim IP, fail2ban executes its ban action (typically iptables -I f2b-sshd -s VICTIM-IP -j REJECT). The legitimate user at that IP can no longer reach SSH on the target host. The ban persists for bantime (default 10 minutes, often configured longer). The attacker can repeat this for multiple victim IPs to cause wider disruption.- fail2ban ban action is functional (iptables/nftables/firewalld)
- Victim IP is not whitelisted in fail2ban's
ignoreipsetting
- Well-configured deployments whitelist admin/management subnets in
ignoreip - Short default
bantime(600s) limits the disruption window - Admins can access the host via console, out-of-band management (IPMI/iLO/iDRAC), or from a different IP
/var/log/fail2ban.log) will show the victim IP being banned — if the victim IP is a known admin IP, this is anomalous and detectable/etc/fail2ban/filter.d/sshd.conf (or create sshd.local to override) and replace the __on_port_opt and __suff definitions: set __on_port_opt = (?: port \d+)? and __suff = %(__on_port_opt)s(?: \[preauth\])?\s*. Then fail2ban-client reload sshd. This is a config-file-only change with zero downtime. Since the noisgate verdict is MEDIUM, there is no mitigation SLA — go straight to the 365-day remediation window, but this one-line fix can be deployed in minutes via config management./etc/fail2ban/jail.local, set ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 YOUR-ADMIN-SUBNETS. This prevents fail2ban from ever banning IPs in those ranges regardless of misattributed log entries. Reduces the attack to banning only non-whitelisted IPs — which is far less operationally impactful. Deploy within the 365-day noisgate remediation SLA.MaxStartups 10:30:60 in sshd_config and add iptables/nftables rate limiting (-m recent --seconds 60 --hitcount 10). This throttles how quickly an attacker can generate the crafted login attempts needed to hit maxretry, buying time for detection. Does not eliminate the vulnerability but raises the practical cost of exploitation.Invalid user field contains an embedded IP address pattern (e.g., regex Invalid user.*\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}.*on). This detects exploitation attempts in near-real-time and enables rapid fail2ban unban or attacker IP blocking. Detection-only control; does not prevent the ban but enables fast recovery.- Upgrading fail2ban to latest package version — as of 2026-10-18, no tagged release incorporates the fix. The fix is in git commits only; distro packages for Debian/Ubuntu/RHEL have not issued backport advisories yet. You must patch the filter file manually or pull from git main.
- Switching to
banaction = firewallcmd-ipsetor other ban action — the vulnerability is in the *filter regex* that misidentifies the source IP, not in the ban action mechanism. Changing how bans are enforced does not fix what IP gets banned. - Disabling password authentication in sshd — OpenSSH still logs
Invalid userentries even whenPasswordAuthentication nois set, as long as the connection attempt occurs. The username is logged before the auth method is negotiated.
The supporting signals.
| In-the-wild exploitation | No evidence. Not listed in CISA KEV. No campaigns or threat actor usage documented as of 2026-10-18. The low EPSS and absence from threat intel feeds suggest this remains theoretical. |
|---|---|
| Proof of concept | No formal PoC repos found on GitHub, pocindex.io, ExploitDB, or Nuclei templates. However, the "exploit" is trivially obvious and requires no tooling — a single ssh command with a crafted username is sufficient: ssh 'x VICTIM-IP on'@target. The commit message from sebres (fail2ban maintainer) includes a test case demonstrating the attack vector. |
| EPSS | 0.00314 (0.31%) — 22.7th percentile. Very low predicted exploitation probability in the next 30 days. |
| KEV status | Not listed. No CISA Known Exploited Vulnerabilities entry. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L — Network attack vector, low complexity, no privileges/interaction needed, but impact capped at Low availability only. No confidentiality or integrity impact. Scope unchanged. |
| Affected versions | fail2ban 0.10.5 through 1.1.1. This spans roughly 6 years of releases. The vulnerable regex was introduced in the __on_port_opt and __suff patterns in config/filter.d/sshd.conf. |
| Fixed versions | Commits ddd879d and f609786. No tagged release yet — fix is in git main only. No Debian/Ubuntu security advisories (DSA/USN) observed as of 2026-10-18; distro backports are pending. |
| Scanning/exposure data | No GreyNoise or Shodan tags specific to this CVE. SSH on port 22 is massively exposed (~21M hosts per Shodan), but fail2ban installation cannot be fingerprinted remotely. The vulnerable *population* is a subset of SSH-exposed Linux hosts running fail2ban 0.10.5–1.1.1. |
| Disclosure timeline | 2026-10-13: CVE published, NVD entry created. 2026-10-16: NVD last modified (awaiting analysis). Patch commits appear to predate the CVE assignment. |
| Researcher / reporter | The fix was authored by sebres (fail2ban core maintainer). Original reporter referenced via coredump.ws/repos/mail-hardening.git. |
Sources.
Why this verdict
- Trivial weaponization, zero-auth attack: The exploit requires nothing more than
ssh 'x VICTIM-IP on'@target— no tooling, no PoC to compile, no authentication. This is as low-friction as remote attacks get, which justifies the Network/Low-Complexity/No-Privileges vector components at face value. - Impact ceiling is firmly Low availability: There is no path from this bug to code execution, privilege escalation, credential theft, or data exfiltration. The worst outcome is a targeted SSH lockout of specific IPs on specific hosts. CVSS correctly caps this at C:N/I:N/A:L.
- Friction: attacker's own IP races against victim IP for banning: The attacker's real source IP also appears in the same log line. Depending on fail2ban's match ordering, the attacker may ban themselves before accumulating enough misattributed hits against the victim. This is a non-trivial operational friction that CVSS doesn't capture.
- Friction:
ignoreipwhitelist breaks the chain for managed environments: Well-configured fail2ban deployments whitelist admin/management subnets viaignoreip. Any IP in that list cannot be banned regardless of how many misattributed failures the attacker generates. - Friction: short default bantime and out-of-band recovery: Default
bantimeis 600 seconds. Even if an admin is locked out of SSH, they can access the host via console, IPMI/iLO/iDRAC, or from a different source IP. The disruption window is bounded. - Role multiplier: fail2ban is a host-level intrusion prevention utility, not a high-value-role component (not an IdP, DC, hypervisor, CI/CD system, PKI, backup, EDR, or network edge appliance). Its deployment roles span: (a) *low-value* — personal VPS, dev boxes; (b) *typical* — web servers, app servers with SSH exposed; (c) *highest-value plausible* — bastion/jump hosts or production database servers. Even on a bastion host, the blast radius is SSH access denial for specific IPs — host-level, temporary availability impact, not domain takeover, fleet compromise, or data egress. This does NOT trigger the HIGH floor because no realistic deployment-role outcome reaches domain/fleet/supply-chain scale impact.
- No exploitation signal reinforces vendor baseline: EPSS 22.7th percentile, no KEV listing, no PoC repos, no campaign reports. The theoretical ease of exploitation has not translated into observed adversary interest.
Why not higher?
Upgrading to HIGH would require either a path to confidentiality/integrity impact or a blast radius exceeding individual-host SSH availability. Neither exists. The bug cannot be chained into code execution, authentication bypass, or lateral movement. Even the most aggressive scenario — locking admins out during active incident response — produces temporary SSH inaccessibility on individual hosts with multiple recovery paths (console, IPMI, alternate IPs, manual fail2ban-client unban). The component is not a high-value-role target where availability loss cascades to fleet-scale or domain-scale impact.
Why not lower?
Downgrading to LOW would undervalue the zero-authentication, zero-complexity, network-reachable attack surface. An internet-facing attacker can disrupt SSH access to any fail2ban-protected host without credentials, and the affected version range (0.10.5–1.1.1) spans ~6 years of releases on a widely-deployed tool. The attack is operationally useful as a harassment technique against administrators or as a diversionary tactic during multi-stage intrusions. The trivial exploitability prevents this from falling below MEDIUM.
Crowdsourced verification payload.
Run this script on each target host running fail2ban. No special privileges needed — it reads the filter config file. Usage: bash check_cve_2026_109786.sh. Exit code 1 = VULNERABLE, 0 = PATCHED, 2 = UNKNOWN.
#!/bin/bash
# CVE-2026-109786 — fail2ban sshd filter log-injection check
# Detects whether the vulnerable "on \S+" regex is present in the sshd filter.
# Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN
set -euo pipefail
FILTER_PATHS=(
"/etc/fail2ban/filter.d/sshd.conf"
"/etc/fail2ban/filter.d/sshd.local"
"/usr/local/etc/fail2ban/filter.d/sshd.conf"
"/usr/local/etc/fail2ban/filter.d/sshd.local"
)
FOUND=0
VULN=0
for fpath in "${FILTER_PATHS[@]}"; do
if [ -f "$fpath" ]; then
FOUND=1
# Check for the vulnerable 'on \S+' pattern in __suff or __on_port_opt
if grep -qE 'on\s+\\S\+' "$fpath" 2>/dev/null; then
echo "VULNERABLE — $fpath contains 'on \\S+' pattern (CVE-2026-109786)"
VULN=1
else
echo "PATCHED — $fpath does not contain vulnerable 'on \\S+' pattern"
fi
fi
done
if [ "$FOUND" -eq 0 ]; then
if command -v fail2ban-client &>/dev/null; then
VER=$(fail2ban-client --version 2>/dev/null | head -1 || echo "unknown")
echo "UNKNOWN — fail2ban installed ($VER) but sshd filter not found at expected paths"
exit 2
else
echo "UNKNOWN — fail2ban does not appear to be installed"
exit 2
fi
fi
if [ "$VULN" -eq 1 ]; then
if command -v fail2ban-client &>/dev/null; then
VER=$(fail2ban-client --version 2>/dev/null | head -1 || echo "unknown")
echo "Installed version: $VER"
fi
echo "RESULT: VULNERABLE"
exit 1
else
echo "RESULT: PATCHED"
exit 0
fi