Maltrail watches the traffic on a network you run and raises an event whenever a machine talks to known bad infrastructure. It matches domains, URLs, IP addresses, IP:port pairs and User-Agent strings against more than 1.5 million indicators, called trails, built from a curated static set of over 3,000 files plus 39 public feeds such as abuse.ch's URLhaus and SSL Blacklist, Spamhaus, FireHOL and Emerging Threats. Heuristics on top catch things no list has yet: port scans, DGA-looking lookups, DNS exhaustion, suspicious downloads and odd User-Agents. A hit reads like a log line: this internal address looked up this domain, and that domain belongs to this malware family.
There are two parts. A sensor, rewritten in Rust on libpcap, sits on a mirror port, a gateway or any busy host and does the capture and matching; a Python server collects events from one or many sensors and serves a browser dashboard with live updates, search, retro hunting across past days, a world map, triage notes and CSV or JSON export. Events can also go out as CEF over syslog or JSON to Logstash for an existing SIEM. The sensor is small enough to run on a 256 MB Raspberry Pi.
It comes from Miroslav Stampar, co-author of sqlmap, and has been maintained since 2014, now with Mikhail Kasimov: about 8,600 stars, a 3.5 release in October 2026 and a push on the day of our scan. It is MIT-licensed, and the trail lists themselves are published openly in the stamparm/trails repository.
- Repository: github.com/stamparm/maltrail
- Licence: MIT (MIT License)
- Language: Python. Stars: 8,647. Forks: 1,268. Last push: Oct 28, 2026.
- Scan: safe, Oct 28, 2026, commit 0435011
Who it is for
Network and security admins at small and mid-sized organisations who want malware detection without a commercial NDR product, home-lab and small office users watching their own LAN, and SOC teams who want an indicator-based sensor that feeds their existing SIEM.
Getting started
1. Install the server and sensor on Linux, macOS or a BSD (it prints the generated admin password once)
curl -fsSL https://raw.githubusercontent.com/stamparm/maltrail/master/install.sh | sudo sh2. Or read the installer first: from a clone, a dry run prints every command without changing anything
git clone --depth 1 https://github.com/stamparm/maltrail.git && cd maltrail && sh install.sh --dry-run3. Or run the supplied Docker Compose deployment
docker compose -f docker/docker-compose.yml up -d4. Open the dashboard once the first trail build finishes (a few minutes)
open http://127.0.0.1:8338The installer runs as root to install packages, create a maltrail user and systemd services, and give the sensor packet-capture capabilities. The shipped config listens on every interface over plain HTTP, and its admin / changeme! login works only from the server itself; set your own users and put it behind TLS before using it across a network. Windows uses install.ps1 and needs Npcap installed first. Only capture traffic on networks you own or administer.
Safety scan
We cloned stamparm/maltrail at commit 0435011 on Oct 28, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.
- The one secret candidate is a test, not a key. tests/test_common.py writes a fake BEGIN PRIVATE KEY block containing the text not base64 at all to prove a checker does not crash. That checker exists because older Maltrail versions shipped a TLS key in misc/server.pem from 2020 until it was removed; the server now refuses to start with that published key or certificate, and the test guards the fingerprints.
- All 12 pattern hits are explained. Seven curl | sh hits are comments and usage hints in install.sh and core/testing.py, and two more are detection rules: core/settings.py and its Rust twin sensor/src/settings_gen.rs contain a regex that flags remote code execution attempts in HTTP traffic, which naturally names wget http, curl -O and xp_cmdshell. The three persistence hits are the installer enabling its own systemd services and a comment in its test harness. The one bare-IP URL is a sample URLhaus feed row in tests.
- install.sh is about 940 lines, needs root, and pipes to sh by design; it verifies the SHA-256 of the prebuilt sensor it downloads, offers --dry-run and --uninstall, and runs as an unprivileged user afterwards with only CAP_NET_RAW and CAP_NET_ADMIN on the sensor. install.ps1 does the same on Windows, also checksum-verified, and runs the sensor at boot as SYSTEM. sensor/build.rs only probes for libpcap so a missing package gives a readable warning.
- sensor/Cargo.lock pins 62 crates with one known advisory, a moderate panic bug in block-buffer, which ships in the sensor through the SHA and HMAC crates it uses for TLS fingerprints and event signing. Nothing critical or high. The server is plain Python with no third-party packages to lock.
- Eight workflows, none using pull_request_target; only 1 of 26 third-party action uses is pinned to a commit. Security policy, CodeQL, Bandit, licence, contributing guide and code of conduct present; no Dependabot. The network hosts in the scan are the threat feeds and GitHub, where trail updates come from daily.
What the scanner counted
| Check | Result |
|---|---|
| Secrets | 1 candidate found and read; see the notes above. |
| Suspicious code | 12 pattern hits found and read; every one is listed under the raw findings. |
| Install-time code | 1 Cargo build script. 2 installer scripts (one fetches and runs a remote script; one can call sudo) |
| Committed binaries | None. |
| CI workflows | 8 workflows. None use pull_request_target. 25 of 26 third-party actions pinned to a tag rather than a commit. |
| Network hosts | 40 distinct hosts referenced from source; most often github.com, example.invalid, raw.githubusercontent.com, dataplane.org. 1 URL to a bare IP address, listed under the raw findings. |
| Known vulnerabilities | 1 advisory across 62 pinned packages: 0 critical, 0 high, 1 moderate, 0 low. sensor/Cargo.lock: 62 packages, 1 advisories. |
| Project hygiene | Has security policy, CodeQL, licence file, contributing guide. Missing automated dependency updates. |
| OpenSSF Scorecard | 4.8 out of 10, as of Oct 26, 2026. |
The raw findings
Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.
Secret candidates (1, redacted)
| Where | Rule | Match |
|---|---|---|
| tests/test_common.py:252 | private-key | -----B…--- (27 chars) |
Pattern hits (12)
| Where | Rule | Match |
|---|---|---|
| core/settings.py:155 | download-piped-to-shell | ("potential remote code execution", r"\$_(REQUEST|GET|POST)\[|xp_cmdshell|shell_exec|exec_code|shell:::\{|oscmd\(|\bping(\.exe)? -[nc] \d+|timeout(\.exe)? /T|tf… |
| core/testing.py:429 | download-piped-to-shell | print("[?] (hint: \"curl -sSL https://raw.githubusercontent.com/stamparm/maltrail/master/install.sh | sudo sh\", or \"cargo build --release --manifest-path sens… |
| install.sh:5 | download-piped-to-shell | # curl -fsSL https://raw.githubusercontent.com/stamparm/maltrail/master/install.sh | sh |
| install.sh:135 | download-piped-to-shell | # `curl | sh` never matches: $0 is "sh" or "-" there, not a readable file. |
| install.sh:149 | download-piped-to-shell | die "this needs root. Re-run with: curl -fsSL <url> | sudo sh" |
| install.sh:208 | download-piped-to-shell | # kind of detail that turns "curl | sh" into a support thread. |
| install.sh:471 | download-piped-to-shell | # exists to absorb; leaving it to the operator is how "curl | sh" earns its reputation. |
| install.sh:797 | persistence | run systemctl enable --now "maltrail-$role.service" || warn "maltrail-$role did not start; see 'journalctl -u maltrail-$role'" |
| install.sh:854 | persistence | info "start systemctl enable --now maltrail-server maltrail-sensor" |
| install.sh:934 | download-piped-to-shell | # Called on the last line so a truncated `curl | sh` cannot execute half an installer. |
| sensor/src/settings_gen.rs:285 | download-piped-to-shell | r#"\$_(REQUEST|GET|POST)\[|xp_cmdshell|shell_exec|exec_code|shell:::\{|oscmd\(|\bping(\.exe)? -[nc] \d+|timeout(\.exe)? /T|tftp -|wget http|curl -O|sh /tmp/|tou… |
| tests/install/run.sh:19 | persistence (test/example) | # checked there; `systemctl enable --now` is not exercised. |
URLs to bare IP addresses (1)
| Where | Rule | Match |
|---|---|---|
| tests/test_feeds.py:31 | ip-literal-url | "3301234","2026-10-26 12:58:04","http://1.2.3.4:41234/i","online","2026-10-26 12:58:04","malware_download","32-bit,elf,mips,Mozi","https://urlhaus.abuse.ch/url/… |
Installer scripts (2)
- install.ps1, 322 lines; talks to api.github.com, github.com, npcap.com
- install.sh, 938 lines, uses sudo, fetches and runs a remote script; talks to github.com, raw.githubusercontent.com
Worst known vulnerabilities (1 of 1)
| Advisory | Severity | Package | Summary |
|---|---|---|---|
| GHSA-qwgh-2vcv-g2f7 | moderate | block-buffer@0.10.4 | block_buffer: panic corrupts inline buffer position |
By the numbers
| Stars | 8,647 |
|---|---|
| Forks | 1,268 |
| Contributors | 8 |
| Commits | 703 |
| Open issues | 37 |
| Open pull requests | 1 |
| Releases | 15 |
| Latest release | 3.5 |
| Licence | MIT |
| Main language | Python |
| Project age | 11 years |
| Last push | Oct 28, 2026 |
| Tracked files | 390 |
| Lines of code | 81.5K |
| Checkout size | 7 MB |
Lines by language: Rust 32.9K, Python 31.3K, JavaScript 5,561, Markdown 3,935, Shell 2,366, YAML 2,085.
Questions
Is Maltrail free?
Yes. Maltrail is MIT-licensed and free for any use, including commercial networks, and the public feeds it uses are free. A few optional integrations, such as some abuse.ch services, ask for a free account key.
Is it legal to monitor network traffic with Maltrail?
On a network you own or administer, generally yes, and it is what intrusion detection is for. Capturing other people's traffic without authority is illegal in most countries, and even on a work network you may need to tell users and follow your organisation's privacy and monitoring rules. Maltrail stores events about matched traffic, not full packet captures.
Will Maltrail block malicious traffic?
No. It is a passive detection system: it watches a copy of the traffic and reports what it sees. It is not a firewall or intrusion prevention system and does not replace endpoint protection, though its events and exported indicators can feed a firewall, a SIEM or your own blocking scripts.
This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.
