← tools

shellsift

live Go GitHub →

A local auth-log anomaly hunter — parses sshd and auth logs for brute-force patterns, off-hours logins, and impossible travel. Nothing leaves the box.

What it does

shellsift reads your auth logs locally — no agent, no cloud, no data shipping anywhere — and surfaces patterns that typically get buried in log noise:

  • Brute-force detection — N failed login attempts from a single source IP within a sliding time window (configurable, default: 5 attempts within 60 seconds)
  • Off-hours logins — successful logins during a defined out-of-hours window (configurable per host)
  • Impossible travel — a source IP appearing in two geographically distant locations within too short a time window to be real (uses offline GeoLite2 — no external API calls)
  • Per-IP summary — total attempts, first/last seen, resolved ASN, and a risk-level indicator

Everything runs from a single binary against log files on disk. Useful in three contexts: post-incident review, regular health checks of internet-facing SSH hosts, and as a lightweight IDS component that doesn’t require a full SIEM.

Installation

Download the latest binary from the GitHub releases page and drop it anywhere in your PATH:

curl -Lo shellsift https://github.com/compilelog/shellsift/releases/latest/download/shellsift-linux-amd64
chmod +x shellsift
sudo mv shellsift /usr/local/bin/

Or build from source (requires Go 1.22+):

git clone https://github.com/compilelog/shellsift
cd shellsift
go build -o shellsift .

GeoLite2 database (required for impossible-travel detection only):

shellsift --download-geodb   # downloads to ~/.config/shellsift/GeoLite2-City.mmdb

Usage

Analyse a single log file and print a report:

shellsift /var/log/auth.log

JSON output for piping:

shellsift /var/log/auth.log --format json | jq '.brute_force | .[] | select(.attempts > 20)'

Analyse multiple files (e.g. rotated logs):

shellsift /var/log/auth.log /var/log/auth.log.1 /var/log/auth.log.2.gz

Configure thresholds with a config file:

# ~/.config/shellsift/config.yaml
brute_force:
  threshold: 10
  window: 120s
off_hours:
  start: "22:00"
  end:   "06:00"
  timezone: "Europe/London"

Run shellsift with the config explicitly:

shellsift --config ~/.config/shellsift/config.yaml /var/log/auth.log

Licence: MIT — See the GitHub repository for full licence text.

Changelog

v1.2.0
2026-05-10
  • Added impossible-travel detection using offline GeoLite2 lookups — flags source IPs that appear in geographically impossible sequence within a configurable time window
  • Off-hours detection window is now configurable per-host via config file (was hardcoded 22:00–06:00)
  • Report output now includes per-IP summary table with total attempts, first/last seen, and ASN
v1.1.0
2026-03-22
  • JSON output mode added (`--format json`) — pipe into jq, SIEM, or anything else
  • Brute-force threshold is now configurable per source IP range (`--threshold 5` globally or per CIDR block in config)
  • Fixed edge case where IPv6-mapped IPv4 addresses (`::ffff:x.x.x.x`) were counted as separate source IPs from their IPv4 equivalents
v1.0.0
2026-02-01
  • Initial release — sshd `auth.log` parsing, basic brute-force detection (N failed attempts from same IP within window)
  • Plaintext and Markdown report output
  • Single static binary, no dependencies beyond the log file