Mailstrix

Hunting OLE & VBA threats in email.

Mailstrix recursively unpacks every attachment down to its cleartext payload — macros, archives, obfuscated office docs — then matches it with YARA. It sees the malware your content filters never decode.

GitHub Docker Hub Docs & syntax MyGUARD
Mailstrix owl mascot inspecting a malicious email attachment with a magnifying glass

Deep recursive extraction

OLE, OOXML, RTF, XLM, BIFF and VBA pulled apart and decompressed to cleartext — the real moat, not the matcher.

Archive unpacking

zip, rar, 7z, cab, jar, apk, tar, gz — including nested batch droppers, scanned to the bottom layer.

OneNote & TNEF

Parses the formats attackers abuse precisely because most scanners don't look inside them.

PE/ELF carving

Carves embedded executables out of containers and documents for direct inspection.

YARA matching

Swappable YARA back-end runs against the decoded cleartext, so obfuscation doesn't hide the signature.

URLhaus lookup

Optional abuse.ch malware-URL intelligence on links found inside extracted content.

MalwareBazaar lookup

Hashes every attachment and checks the SHA-256 against the abuse.ch MalwareBazaar corpus — known samples flagged instantly.

Out-of-process by design

Scans over HTTP so your mail event loop never blocks and libyara stays out of the gateway image — the gozer/DRP pattern.

Filename-aware rules

Maps the attachment name to YARA filename/extension externals, so name-keyed THOR / Loki rules fire correctly.

Verdict cache + coalescing

LRU+TTL cache with optional Redis L2 and singleflight — a message to N recipients is scanned once, not N times.

Prometheus metrics

A /metrics endpoint exposes scans, matches, errors, cache hits and feed stats — drop straight into Grafana.

Fail-open & hot reload

Parse errors never block mail; a SIGHUP reloads rules and flushes the cache with zero downtime.

Five ways to deploy

Run it

docker run -d --name mailstrix \
  -p 8079:8079 \
  eilandert/mailstrix:latest

Also ships as a Debian package and a Helm chart. See the full syntax & synopsis for every environment variable, CLI subcommand and HTTP endpoint, or the GitHub repository for full deployment docs.

FAQ

What is Mailstrix?

A standalone mail-attachment malware scanner. It recursively unpacks attachments to their cleartext payload and matches them with YARA, catching malware hidden inside macros, archives and obfuscated office documents.

How does it integrate with my mail stack?

Five ways: an rspamd Lua module, a SpamAssassin Perl plugin, a Dovecot Sieve wrapper, an ICAP service, or a standalone daemon and scanner CLI.

What YARA rulesets are included?

The image bakes ~10,000 public rules from eight curated sources at build time, precompiled to .yac and rebuilt daily. Mailstrix doesn't author rules — it packages other people's work, and every set keeps its own upstream license:

RulesetSourceLicense
YARA-ForgeYARAHQ/yara-forgeaggregator (each rule keeps its upstream license)
signature-baseNeo23x0/signature-baseDRL 1.1
Didier Stevens SuiteDidierStevens/DidierStevensSuitepublic domain
bartblaze/Yara-rulesbartblaze/Yara-rulesMIT
InQuest yara-rules-vtInQuest/yara-rules-vtMIT
ANY.RUNanyrun/YARAper-repo
CAPEv2 (curated)kevoreilly/CAPEv2per-repo
YARAifyabuse.ch YARAhubCC0

Any source can be pinned or toggled off with a build arg (YARAFORGE_SET, DIDIER=0, BARTBLAZE=0, INQUEST=0, YARAIFY=0, …).

What does it cost? What's the license?

Free and open source. Mailstrix itself is MIT. Dependencies are permissive (go-yara BSD-2, oleparse MIT, the Redis client BSD/Apache). The baked rule sets keep their own upstream licenses — see the ruleset table above.

Money for coffee is always appreciated though — there's a donate button on the contact page. And if you're really making big bucks off this, don't forget us! We need a coffee drip :-)

Why does it run as a separate service instead of inside the MTA?

libyara is a C library (CGO). Running it inside an rspamd or Dovecot worker would block the event loop and drag a heavy C dependency into the mail image. As a separate HTTP service the caller stays async, the scanner scales independently, and the MTA image stays lean. The Sieve/LDA path uses strix-scan, a CGO-free client, for boxes that can't link libyara at all.

How do I keep the scanner secure?

Set MAILSTRIX_TOKEN (or MAILSTRIX_TOKEN_FILE); callers must then send it as a Bearer header or X-MAILSTRIX-Token. The body size is capped (MAILSTRIX_MAX_BODY) and concurrency is gated, because anyone who can reach the port can submit CPU-costly scans. Bind it to a private network or loopback — never expose /scan to the public internet.

How much does it scan, and how fast?

Work scales with the effort level (1 = raw bytes + shallow extraction, max = full recursive depth). Set MAILSTRIX_EFFORT=auto and it derives the level from admission-gate pressure — full depth when idle, shedding a level at a time as in-flight scans fill the gate and climbing back as it drains. MAILSTRIX_MAX_CONCURRENT (default = CPU count) gates libyara scans and MAILSTRIX_MAX_INFLIGHT (default 2×) is the admission gate. Sizing profiles with expected p95 and RPS are in the README.

What happens if a scan errors or times out?

It fails open, always. A scan error, timeout, or libyara panic is reported as "no match" rather than blocking the message — a malware scanner must never become a mail-delivery outage. Errors are still counted in Prometheus so you can alert on them.

Which platforms are supported?

Linux on amd64 and arm64. Every release ships a Docker image, a Debian/Ubuntu .deb for both arches, and static strixd / strix-scan binaries with SHA256SUMS. A Helm chart is included for Kubernetes.