Skip to content

Releases: selfhostr/suckerpot

v0.9.0

Choose a tag to compare

@github-actions github-actions released this 04 Nov 20:38

Participant installs are now safe to run on a home machine: the installer checks that the internet reaches the sensors, offers a host firewall, and every internal network is isolated from the host.

Updating an existing install: Docker cannot change an existing network, so the first update recreates the stack once (down, never -v; data volumes are kept). Docker Engine 28 or newer is needed for the network isolation. See Updates.

Added

  • ./scripts/participant.sh ports-check [--wait SECONDS] [--since ISO | --since-install] tells whether the internet reaches your sensors, and the participant installer runs it at the end and offers to re-check after you open the ports on your router. It makes no outside connection: it counts sessions from public addresses that your sensors already recorded, prints no address, reads the database in a read-only transaction, and exits 0 (reached) or 3 (nothing yet). status.sh points to it.

Changed

  • The participant installer no longer prints a fixed "14 days" date. The hub decides the probation period; ./scripts/status.sh shows the date from which the sensor counts.
  • Participant docs and installer summary: use port forwards rather than a DMZ, explain the DMZ risk, and say precisely when the route-out restriction holds (host firewall loaded) and that the firewall does not filter internet traffic to the machine's own services.

Security

  • Host firewall for participant mode: scripts/host/firewall-participant.nft loads with no placeholder other than the admin SSH port, rendered by scripts/host/render-firewall.sh and installed with scripts/host/install-firewall.sh (systemd unit, survives a reboot, --uninstall to undo). In its own nft table, it drops everything new, invalid or untracked from the sensors' uplink to the host and to the internet or the LAN, and limits hubproxy's uplink to TCP 443 on public addresses plus UDP DNS to the resolvers Docker uses. The full-mode template's DNS rule is narrowed the same way. The renderer refuses a host bridge that is not Docker's but matches the rule names, to avoid a lockout.
  • Every internal network has an isolated gateway (gateway_mode_ipv4: isolated), a fixed bridge name and IPv6 off, so a compromised container no longer reaches services on the host through its bridge. This needs Docker Engine 28 or newer, and the first update recreates the stack once (see docs/updates.md).
  • A guardrail checks the hardening of every service of every supported stack: read-only root, all capabilities dropped, no-new-privileges, a non-root uid:gid, memory, CPU and process limits, a healthcheck, noexec,nosuid,nodev tmpfs, no host namespaces, devices, Docker socket or unlisted bind mounts, isolated internal networks, and third-party images pinned by digest.
  • The TimescaleDB image is pinned by digest.
  • The installers offer to install the host firewall at the end (participant mode; asks before using sudo, never blocks, prints the two commands otherwise; participant.sh vpn reminds you to re-run it), and ./scripts/participant.sh firewall [install|uninstall|status] does it later.
  • Updates and rollbacks recreate the stack once (down --remove-orphans, never -v) when compose says an existing network cannot be reused (matched on its wording, not on any mention of a network); a foreign container attached to one of our networks stops the run with instructions instead of being disconnected.
  • CI pins the TimescaleDB test image by digest, like docker-compose.yml.
  • Automatic updates: the minimum release age is now at least 48 h whatever the release's own manifest says; AUTO_UPDATE_MIN_AGE_H in .env can raise it.
  • Automatic updates: a release that is unsigned, does not match its tag or has a signature cosign rejects is marked bad with its reason (network, Docker, Sigstore or disk problems are never held against a release) and the next newest release of the same major version is tried (3 at most per run), so one bad tag no longer blocks updates.
  • The installer warns when Docker Engine is older than 28, where internal networks are not isolated from the host.

Verify: scripts/verify-release.sh v0.9.0 and just verify-images v0.9.0.

Full Changelog: v0.8.0...v0.9.0

v0.8.0

Choose a tag to compare

@github-actions github-actions released this 04 Nov 18:10

SuckerPot now lives in the Selfhostr organisation: github.com/selfhostr/suckerpot, images at ghcr.io/selfhostr/suckerpot-*, site, docs and demo at https://suckerpot.selfhostr.io/.

Updating from v0.7.1 or earlier: set SUCKERPOT_IMAGE_PREFIX=ghcr.io/selfhostr/suckerpot and UPDATE_CHECK_REPO=selfhostr/suckerpot in .env, run git remote set-url origin https://github.com/selfhostr/suckerpot.git, then just update. The signature check refuses the new release until you do: see Moving from the old repository.

Changed

  • The offline mock-data demo moved to https://suckerpot.selfhostr.io/demo/. GitHub Pages and site/ are removed from the repo (the product site is maintained separately).
  • Documentation moved from Read the Docs to https://suckerpot.selfhostr.io/docs/ (Selfhostr docs kit, Starlight). .readthedocs.yaml, docs/conf.py, docs/requirements.txt and the Sphinx CI job are removed; docs/ stays the source.
  • The project moved from github.com/Theroxat/suckerpot to github.com/selfhostr/suckerpot. Release images are now published as ghcr.io/selfhostr/suckerpot-* and signed by the release workflow of the new repository, and the documentation is at https://suckerpot.selfhostr.io/docs/. scripts/env-migrate.sh rewrites the old default SUCKERPOT_IMAGE_PREFIX and UPDATE_CHECK_REPO in an existing .env; the signature checks are as strict as before (exact repository, release.yml, exact tag). An install on v0.7.1 verifies releases against the old repository, so its first update needs SUCKERPOT_IMAGE_PREFIX=ghcr.io/selfhostr/suckerpot set in .env by hand; see docs/updates.md.
  • The network is now called the SuckerPot network, and the blocklists the SuckerPot blocklists. Selfhostr is the small organisation that makes SuckerPot, no longer the name of the product or the network.
  • New addresses: the site is https://suckerpot.selfhostr.io/ (hosted on Cloudflare Pages), the hub is https://suckerpot-hub.selfhostr.io and the feeds are https://suckerpot-feeds.selfhostr.io/v1. The old selfhostr.io site, hub.selfhostr.io and feeds.selfhostr.io are gone. Nodes pick up the new hub address with the next release; the hub keys are unchanged. abuse@selfhostr.io stays.

Verify: scripts/verify-release.sh v0.8.0 and just verify-images v0.8.0.

Full Changelog: v0.7.1...v0.8.0

v0.7.1

Choose a tag to compare

@github-actions github-actions released this 04 Nov 10:46

Full Changelog: v0.7.0...v0.7.1

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 04 Nov 09:20

Full Changelog: v0.6.0...v0.7.0

v0.6.0

Choose a tag to compare

@github-actions github-actions released this 03 Nov 17:35

Full Changelog: v0.5.0...v0.6.0

SuckerPot v0.3.0

Choose a tag to compare

@Theroxat Theroxat released this 01 Nov 06:28

Changed

  • just test-integration uses docker-compose.it.yml, an overlay that keeps redis on the backend network only, so the throwaway project fits in Docker's default address pools next to the live stack.
  • The sidebar is grouped into ten entries. Related pages sit behind one entry with tabs: Attacks (Sessions, Attackers, Networks), Campaigns (Campaigns, Techniques), Tools (Scripts, Malware, Infrastructure), Trends (Activity, Patterns), Protection (Blocklists, Detections) and Exposure (Your exposure, CVE watch). Every old URL still works; /attackers?view=asns now redirects to /networks.
  • Today is a visual story of the last 24 hours in plain words: a flow from country to service to how far each visit got, an hour-by-hour strip, and three to five stories of the day with their technical details one click away. Hard words have a short definition on hover.

Added

  • VPN configuration upload (M23): Settings > VPN takes the WireGuard .conf from your VPN provider, parses it strictly (no PostUp and the like, IP endpoint only, full tunnel) after asking for the password again, and writes it to the new vpn-config volume. The vpn service notices the new file and restarts on it; nothing leaves outside the tunnel during the switch, and the API gets no Docker socket. A new exit address stays blocked until the owner trusts the /24 the gate observed (table egress_trusted_exits, migration 0020); an exit inside the honeypot's own addresses or in an AS listed in the new EGRESS_DENY_ASNS can never be trusted, and the exit's AS is shown next to it. /api/v1/settings/vpn endpoints, new guardrails.
  • Anonymous reporting (M22): an ingest worker (ABUSE_REPORTS_ENABLED, off by default) finds abuse contacts over RDAP through the egress gate and prepares draft reports per recipient. The new reporting/ package renders plain text, X-ARF v0.2, .eml, STIX 2.1 and MISP JSON and builds password-protected sample bundles. An identity guard checks every artefact before it is returned and fails closed. Learned self terms need the owner's confirmation. The package ships no wording: the owner writes it in Settings > Reporting. Nothing is ever sent by the stack. Migration 0019, /api/v1/abuse endpoints, the Abuse reports page, Export for CERT, the sample bundle and the Reporting tab in Settings, just abuse-guard-check and the ABUSE_* settings.
  • Anonymous egress (M21): a vpn service (WireGuard through gluetun, profile egress) with a kill switch and an HTTP proxy is the only container with a route to the internet. ingest and the new collector go through the proxy, an egress gate pauses outbound work when the tunnel or its exit address looks wrong, and the old egress network is removed. New just guardrails and just egress-check, new host firewall rules for sp-vpn, sp-egress and sp-samples.
  • Payload collection and static analysis (M21): the collector service fetches captured download URLs through the VPN into a quarantine volume (SSRF validator, size, time and rate caps, never executed), and the network-less analyzer service identifies, hashes, scans with YARA, deobfuscates shell scripts and extracts C2 addresses in a limited child process. Migration 0018, roles suckerpot_collector and suckerpot_analyzer, the /api/v1/samples and /api/v1/egress endpoints, a Samples tab, a sample page and an Egress card in Settings. FETCH_PAYLOADS, PAYLOAD_MAX_BYTES and PAYLOAD_TIMEOUT_SECONDS are replaced by COLLECTOR_ENABLED and the COLLECTOR_* and QUARANTINE_* settings.
  • Synology NAS sensor (M20): a fake unpatched Synology NAS on DSM 7.2.1 (Update 11), with the DSM login page and Web API on HTTP 5000 and HTTPS 5001. Logins always fail with real DSM error codes and are recorded. Requests that match the forged-session and SCGI shapes of CVE-2026-13639 and CVE-2026-13684 are tagged synology-exploit, ransomware indicators of the C3RB3R campaign are tagged c3rb3r, and DSM API calls are tagged synology-dsm. Migration 0017 adds the sensor to the inventory.
  • Probable C2 lookups ignore VirusTotal contacts in big shared networks (Google, Cloudflare, Microsoft, Akamai, Fastly, Meta, Apple, from the local ASN database) and CDN or update domains, and clean up already stored rows on start.
  • Probable C2 addresses: for file hashes that VirusTotal or abuse.ch already know, ingest reads which addresses sandboxes saw the malware contact (VirusTotal relationships, ThreatFox botnet_cc), with the same fixed hosts, quotas and 24 h cache as the other intel lookups and no contact with the addresses. New table indicator_contacts (migration 0016), GET /api/v1/indicators/c2, and a blocklist reason "probable C2" (75 for ThreatFox, 40 for VirusTotal, capped at 45 when no sensor computed the hash and fewer than three networks dropped it).
  • GET /api/v1/story, the plain-language summary behind Today.
  • A stage filter on GET /api/v1/sessions and on the Attacks page (looked, guessed, got in, ran commands, tried to install, sent an exploit), plus since and until in the Attacks URL.

Fixed

  • The abuse, alerts and intel workers no longer wait up to an hour for their first run on a host that booted recently.
  • CVE watch: the NVD window is 60 days (was 30) and is read in one-day chunks, oldest first, with a page budget, so a busy day no longer loses CVEs silently at the 10,000-result limit. A run that stops early resumes from its last complete chunk.
  • CVE watch: GitHub advisories are read in seven-day chunks, oldest first. A one-time start-up rewind refills a shallow history, and watched CVEs that are missing from the table are fetched by id (at most 10 per run, once per id per 24 hours).

Docs

  • A "Provider API keys" guide: what each optional key adds and how to get it, step by step.
  • A Troubleshooting section in the deployment guide, and the upgrade command.
  • Refreshed screenshots and a new README gallery for the three-space navigation.

Upgrade: git pull && just up (migrations 0017 to 0020 run automatically). See the deployment guide for the VPN, collector and reporting settings.

Full changelog: v0.2.0...v0.3.0

SuckerPot v0.2.0

Choose a tag to compare

@Theroxat Theroxat released this 26 Oct 04:36

Added

  • Seven more sensors (M9): Redis, Docker Engine API, MySQL, Microsoft SQL Server, Android ADB, SMB and SIP (UDP and TCP), each with real-client tests, per-IP fairness for CPU, memory and events, and a security review. SIP never sends a reply larger than its request.

  • Provider keys in Settings (M11): AbuseIPDB, GreyNoise and MaxMind keys stored encrypted (AES-256-GCM), write-only in the UI, with re-authentication and a "Test key" button.

  • CVE watch (M12): daily CISA KEV, NVD and GitHub advisory feeds ranked by relevance to the emulated services, with "seen in our traffic" counts and a trap-proposal sheet.

  • Indicators and threat intelligence (M13): URLs, domains, IPs and hashes extracted from events, enriched by URLhaus, ThreatFox and VirusTotal, shown on an Infrastructure page with CSV and STIX export. Passive only.

  • Users and roles (M14): admin and read-only viewer accounts, one-time temporary passwords, per-source lockout and an audit log. The .env owner account stays the root of trust.

  • Campaigns and MITRE ATT&CK (M15): sessions that share a script, payload host, hash, malware family, exploit or credential list are grouped into campaigns, with a Techniques heatmap. Off by default (CAMPAIGNS_ENABLED, ATTACK_ENABLED).

  • Defend (M16): scored blocklists, overrides, exports for OPNsense and pfSense aliases, an opt-in token feed (FEEDS_ENABLED), Sigma and Suricata rules marked "review before deploying", and "Your exposure".

  • Script library (M17): command scripts with plain-English explanations, and an optional LLM explainer (LLM_ENABLED, off by default) that sees only normalised script text.

  • Alerts and reports (M18): Discord, Microsoft Teams and e-mail (TLS) channels, alert rules that are off until switched on, a test message button, and a weekly report with a printable view. Off by default (ALERTS_ENABLED, REPORTS_ENABLED).

  • Today, search and research scanners (M19): a Today home page, a global search box, a glossary, and known research scanners labelled benign by network ownership.

  • Migrations 0011 to 0015 add the campaign, ATT&CK, Defend, script, alert and search tables and columns.

  • RDP sensor (M10): the NTLM challenge flow, so nmap --script rdp-ntlm-info returns the full Windows Server 2022 identity and logins arrive as rdp-ntlm events with the user name and domain.

  • RDP decoy accounts (RDP_ACCOUNTS): a login with a decoy password is verified against the NTLM response and tagged weak-credentials. Nothing else is ever checked.

  • Optional NLA-off mode (RDP_NLA_MODE=optional, off by default): records the cleartext user name and password from clients that skip NLA (rdp-nla-off events), tagged rdp-cleartext.

  • RDP client tool identification (nmap, FreeRDP, rdesktop, ncrack, mstsc), stored on sessions as client_tool and shown on the session page.

  • Tag bluekeep for RDP sessions that bind the MS_T120 channel.

  • RDP limit RDP_MAX_TLS_PER_IP (default 4), so a few addresses cannot hold every TLS slot.

Changed

  • Migration 0007 adds the nullable sessions.client_tool column.
  • Live page: the 3D globe is replaced by a flat world map (Equal Earth) with per-country arcs for the last 15 minutes, a stats strip, a ticker of the newest events and rankings of addresses, countries and networks. SITE_HOME_LAT, SITE_HOME_LON, SITE_HOME_LABEL and GET /api/v1/settings/site are unchanged.

Upgrade: git pull --ff-only && docker compose up -d --build — migrations 0006 to 0015 run automatically. New features are switched on with the *_ENABLED variables in .env (see docs/configuration.md); the public blocklist feed and the AI script explainer stay off by default.

🤖 Generated with Claude Code

SuckerPot v0.1.0

Choose a tag to compare

@Theroxat Theroxat released this 25 Oct 03:40

Added

  • Bootstrap (M0) and foundations (M1): MIT licence, project rules, roadmap, architecture and security docs, a gitleaks pre-commit hook and CI; the shared event schema, a Redis Streams pipeline, a TimescaleDB schema with Alembic migrations, an ingest consumer and an API with a live WebSocket feed.
  • Demo data generator (just demo): synthetic sessions across all four sensors with documentation IP ranges only, plus a live mode.
  • SSH sensor: OpenSSH 9.6 fingerprint, configurable weak logins, an emulated shell on a fake filesystem, download recording without fetching, and timed session recording for replay.
  • Telnet sensor: BusyBox telnetd look-alike with Mirai-style flows.
  • Web sensor: byte-identical Apache 2.4.58 with PHP 8.3, fake WordPress and phpMyAdmin pages, and PHP2Shell (upload-progress) detection.
  • RDP sensor: Windows Server look-alike with NLA and username capture.
  • Enrichment: GeoIP and ASN from DB-IP Lite (no key) or MaxMind GeoLite2, optional AbuseIPDB and GreyNoise Community reputation with a 24 h cache and enforced daily quotas.
  • Tagging: a declarative YAML rules engine without regular expressions (recon, mirai, crypto-miner, malware-drop, php2shell).
  • Dashboard: Live (3D globe and event feed), Overview (KPIs and auto-written insights), Attacks, Session detail with terminal replay, Attackers, Trends, Malware (defanged URLs) and Settings, in dark and light on desktop and mobile; a design system; a screenshot mode (?mask=1); Playwright screenshots.
  • Dashboard login: a single admin account with an argon2 password hash, CSRF protection and a rate-limited login.
  • Retention and storage: raw events kept 90 days, aggregates forever, compression, a disk guard, and just backup / just restore.
  • Hardened Docker Compose stack with a host firewall template in scripts/host/.
  • Documentation site (Sphinx, Read the Docs) and a project page.
  • Repository meta: README, CONTRIBUTING.md, SECURITY.md, issue and pull request templates, Dependabot and release-note configuration.

Security

  • No attacker input is ever executed: every sensor passed several rounds of adversarial security review (the web sensor's final review is pending).
  • Isolation: four networks with an internal backend, one Redis ACL user per sensor limited to XADD on its own stream, least-privilege database roles, no outbound route for the API, non-root read-only containers with all capabilities dropped.
  • The first review of the M1 stack found unbounded stream growth, egress, poison-message and default-credential issues; all were fixed and the second pass passed.

Before exposing a host

Read the go-live checklist in the documentation (docs/deployment.md): apply the host firewall template, keep the dashboard port reachable only from your reverse tunnel, generate strong secrets, and run SuckerPot only on an isolated machine you are ready to lose.