Aggregates public YARA rules from many upstream repositories into one validated, deduplicated local rule set, and scans engineering workstations (EWS) and firmware dumps for malware using the YARA-X engine.
Built for OT/ICS incident response, but the rule set is broad general-malware coverage — an EWS is a Windows box, and commodity ransomware/RATs are the more likely find there. ICS malware families (Industroyer, TRITON/TRISIS, Stuxnet, Havex, …) are included and tagged with ATT&CK-for-ICS techniques.
The collector (icsyara update) builds the rule set; the engine
(icsyara scan) uses it. They share nothing but the rules/ directory, so
you refresh rules on one schedule and scan on another.
icsyara update— clones every source insources.yml, splits multi-rule files, compile-validates each rule with YARA-X (broken rules quarantined torules/_broken/), dedupes across sources, and writesrules/plusrules/index.json.icsyara list [--family F] [--sources]— the rule inventory.icsyara scan PATH [--firmware] [--json f] [--csv f] [--max-size MB]— walks a directory/EWS mount concurrently and reports rule matches.--firmwarerunsbinwalkto extract a packed blob first, then scans the extracted tree. Exit code:0clean,1matches found,2error.
| Tool | Why it's needed | Minimum |
|---|---|---|
| Go toolchain | builds the program (uses CGO) | 1.24+ (developed on 1.26) |
YARA-X C API (libyara_x_capi) |
the scanning/validation engine; CGO links to it | 1.19+ |
| C compiler (clang/gcc) | CGO needs it to link the YARA-X library | any recent |
| pkg-config | tells the Go build where the YARA-X library lives | any |
| git | icsyara update clones the rule-source repos |
any |
| binwalk | firmware extraction — only for scan --firmware |
2.x or 3.x |
macOS (Homebrew):
brew install go yara-x binwalk pkg-config
# yara-x ships libyara_x_capi + header + pkg-config file automaticallyLinux (Debian/Ubuntu):
sudo apt-get update && sudo apt-get install -y golang git pkg-config binwalk build-essential
# YARA-X capi is not packaged; build it once with cargo (needs the Rust toolchain):
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # if you don't have cargo
cargo install --git https://github.com/VirusTotal/yara-x yara-x-capi --root /usr/local| Module | Purpose |
|---|---|
github.com/VirusTotal/yara-x/go |
official YARA-X Go bindings (compile + scan) |
gopkg.in/yaml.v3 |
parses sources.yml |
github.com/stretchr/testify, google.golang.org/protobuf |
pulled in transitively (tests / bindings) |
Everything else is the Go standard library. Exact pinned versions live in
go.mod / go.sum.
The Makefile sets PKG_CONFIG_PATH/DYLD_LIBRARY_PATH for the Homebrew
YARA-X automatically:
make build # -> ./icsyara
make update # fetch + validate + index all sources (~45s, ~18k rules)
./icsyara list --sources
./icsyara scan /path/to/ews/mount --json findings.json
./icsyara scan --firmware device_firmware.binIf building without make, export the paths yourself:
export PKG_CONFIG_PATH="$(brew --prefix)/lib/pkgconfig:$PKG_CONFIG_PATH"
export DYLD_LIBRARY_PATH="$(brew --prefix)/lib:$DYLD_LIBRARY_PATH"
go build -o icsyara ./cmd/icsyaraA typical icsyara update yields ~18,400 unique validated rules. Where they
come from:
pie showData
title Rules by source (unique, after validation + dedup)
"Yara-Rules project" : 11323
"signature-base" : 3203
"Elastic protections" : 2407
"ReversingLabs" : 1240
"Mandiant" : 171
"bartblaze / citizenlab / others" : 700
"ICS (ESET, Nozomi, MDudek)" : 158
Sources are listed in sources.yml (signature-base, Yara-Rules,
Elastic protections-artifacts, ReversingLabs, Mandiant, ESET, Nozomi, and
more). The maximal public set is large and some upstream rules are noisy;
the Yara-Rules utils/, email/, crypto/, capabilities/, and
antidebug_antivm/ categories (pure indicator/building-block rules that
match any text or legitimate software) are deliberately excluded. Add or
disable sources by editing sources.yml and re-running icsyara update.
rules/ and cache/ are regenerated by update and are gitignored — the
repo stores no rule bodies, only the source catalog. Each rule's upstream
license is recorded in index.json.
YARA scans bytes at rest — files on an EWS or inside a firmware dump.
It cannot read a running PLC's live fault/diagnostic state; that is a
protocol-level task (S7/Modbus/CIP) handled by the companion
ot-nmap-blue-team toolkit, not this tool.
The scanner's own source code is licensed under the GNU Affero General
Public License v3.0 (AGPL-3.0). See LICENSE. In short: it is
free software — you may use, study, modify, and redistribute it, but any
distributed or network-served modified version must also make its source
available under the same license.
Aggregated YARA rules are NOT covered by this license. They are fetched
at runtime from third-party repositories and each rule retains its own
upstream license (recorded per rule in rules/index.json; the repo-level
license is set in sources.yml). This project does not redistribute any
rule bodies — rules/ and cache/ are generated locally and gitignored.
If you redistribute a generated rule set, you must comply with each upstream
rule's license (GPL-2.0, BSD, MIT, Elastic-2.0, Detection-Rule-License, etc.).
See NOTICE for the source/licence attribution list.
icsyara — public YARA rule aggregator and EWS/firmware scanner
Copyright (C) 2026 Arthur Lin
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version. This program is distributed WITHOUT ANY
WARRANTY; see the GNU AGPL for details <https://www.gnu.org/licenses/>.
