1
0
Fork
You've already forked azoth
0
The world's first open-source ML model for generalized malware detection
Thomas Stromberg 127066a9a7 post-L25 update
2026年07月13日 01:20:53 -04:00
filegroups post-L25 update 2026年07月13日 01:20:53 -04:00
filetypes post-L25 update 2026年07月13日 01:20:53 -04:00
general post-L25 update 2026年07月13日 01:20:53 -04:00
.gitignore
config.json post-L25 update 2026年07月13日 01:20:53 -04:00
ENSEMBLE_MODEL.md move to L25/L3000 2026年07月03日 12:43:33 -04:00
GENERALIST_MODEL.md post-L25 update 2026年07月13日 01:20:53 -04:00
global_policy_metrics.md post-L25 update 2026年07月13日 01:20:53 -04:00
LICENSE
per_filetype_metrics.json post-L25 update 2026年07月13日 01:20:53 -04:00
README.md post-L25 update 2026年07月13日 01:20:53 -04:00
recall_curve.svg post-L25 update 2026年07月13日 01:20:53 -04:00
route_diagnostics.md post-L25 update 2026年07月13日 01:20:53 -04:00
route_policies.json post-L25 update 2026年07月13日 01:20:53 -04:00
route_policies.md post-L25 update 2026年07月13日 01:20:53 -04:00
route_policy_eval_oof.json post-L25 update 2026年07月13日 01:20:53 -04:00
route_policy_eval_oof.md post-L25 update 2026年07月13日 01:20:53 -04:00
slice_metrics.md post-L25 update 2026年07月13日 01:20:53 -04:00
test_metrics.json post-L25 update 2026年07月13日 01:20:53 -04:00
TRAINING.md

Azoth

Static malware detection by routed ensemble. A general LightGBM model scores every file. Per-filetype specialists score files in their domain — PE, ELF, JavaScript, PDF, and 37 more. A file is flagged when any route's score crosses its operating-point threshold.

The point of routing is that the evidence differs by format. A PE's section table is signal. A PDF's stream dictionary is signal. A shell script's token distribution is signal. One generalist trained over all of them learns averages; a specialist trained on one of them learns the format.

Thresholds were fit on a 1,720,070-row dev partition (12.5% of the labeled corpus). The numbers in this README come from a locked 1,719,220-row test partition, disjoint from training and calibration. The bundle is loaded at scan time by litmus. EMBER 2024 reference: Joyce et al., KDD'25.

Use

Input is a JSON report produced by cleave. Output is one verdict — benign or hostile — qualified by a severity level L0..L25000. Litmus reads the hostile threshold at the chosen level (consumers can label anything firing above the configured critical level as suspicious if they want a softer tier); the deployed default is L25 (0.25 FP/M). Lower levels tighten the operating point; higher levels loosen it.

Bundle layout

config.json records the deployed thresholds. Each route lives in its own subdirectory: general/, one of 7 filegroups/<name>/, or one of 41 filetypes/<name>/. A route directory carries two files: model.txt (LightGBM) and feature_spec.json (the features the model expects). Scores are the model's raw probabilities — there is no separate probability calibrator.

Further reading: ENSEMBLE_MODEL.md for routing details, GENERALIST_MODEL.md for the single-model baseline. License: Apache 2.0.

Per-filetype Ensemble Performance

Each row is the routed ensemble's intrinsic ranking quality on that filetype's slice of the locked test partition — PR AUC, ROC AUC, F1 at the F-beta-tuned threshold, and recall at the L25 (0.25 FP/M) operating point. These are properties of the model's scores; how litmus chooses to threshold those scores at each severity level is a runtime concern documented in route_policies.md.

A filetype appears here when it has at least 25 malware and 25 benign in the test slice, or at least 100 of each across the full labeled corpus. Pure archive wrappers (zip, tar, gz, ...), data, and unknown are excluded — their score reflects the container's shape, not the classifier's quality.

Optimization target. Each filetype's ensemble combiner is selected to maximize recall at L25 (0.25 FP/M) on the dev partition, with PR AUC as a tiebreak. Selection is constrained so the ensemble can never report worse than the specialist alone — when no combiner clears the specialist on dev, the ensemble falls back to specialist_priority (which equals the specialist by construction). This matches the deployment budget litmus operates at and the design intent that routing must improve, not degrade, the per-filetype model.

File type Test mal / ben PR AUC ROC AUC F1 Recall @ L25 Δ vs EMBER 2024
html 31 / 2,010 0.994058 0.999928 0.983607 100.00%
rtf 830 / 95 0.998618 0.992023 0.989078 98.31%
pkg_info 1,270 / 1,655 0.995862 0.996702 0.980831 96.30%
package.json 2,515 / 5,974 0.982270 0.983020 0.976368 94.79%
ole_doc 10,604 / 3,904 0.995324 0.986357 0.965762 92.77%
gem 88 / 256 0.967146 0.980291 0.958580 92.05%
elf 23,750 / 58,662 0.997488 0.998429 0.993914 90.60% PR +0.004188 / ROC +0.005129
vbs 1,569 / 460 0.996932 0.989118 0.974149 89.36%
macho 362 / 2,740 0.973984 0.988738 0.950355 87.85%
lnk 569 / 132 0.993218 0.972107 0.975779 85.06%
powershell 727 / 593 0.974305 0.956773 0.937677 80.19%
registry 79 / 15,740 0.926281 0.990142 0.855072 77.22%
perl 46 / 8,638 0.806647 0.943575 0.839506 76.09%
pdf 22,517 / 3,575 0.991369 0.947206 0.960701 74.67% PR -0.001931 / ROC -0.043994
crx 286 / 298 0.947845 0.936617 0.891344 74.13%
tar 3,187 / 7,792 0.972589 0.978552 0.939307 73.52%
shell 2,316 / 16,637 0.940548 0.969834 0.901495 72.93%
npm 521 / 682 0.932682 0.918390 0.864809 67.56%
whl 431 / 815 0.928532 0.932263 0.871429 67.29%
pe 169,247 / 24,513 0.999514 0.996795 0.991745 67.27% PR +0.001214 / ROC -0.001405
python_bytecode 461 / 95,311 0.703858 0.893507 0.792746 64.64%
kotlin 3,890 / 9,191 0.892163 0.899475 0.852911 62.03%
python 2,870 / 67,581 0.793087 0.936401 0.796332 52.89%
zip 13,349 / 3,221 0.950447 0.789528 0.899557 51.12%
php 800 / 69,963 0.742420 0.900377 0.751323 51.00%
ruby 52 / 21,381 0.618497 0.868375 0.681818 48.08%
ooxml 8,559 / 351 0.992692 0.884054 0.992862 46.50%
jar 498 / 2,371 0.879945 0.949773 0.844864 45.98%
cargo.toml 50 / 918 0.531723 0.700773 0.574713 38.00%
csharp 466 / 12,010 0.536387 0.845386 0.516854 28.33%
jpeg 180 / 5,414 0.173810 0.531772 0.240385 21.11%
dockerfile 25 / 554 0.274753 0.705451 0.315789 20.00%
deb 58 / 2,461 0.130624 0.716778 0.158730 17.24%
xml 505 / 46,777 0.126954 0.602914 0.209830 4.75%
text 500 / 34,589 0.085724 0.612855 0.118492 3.80%
go 2,114 / 26,711 0.228728 0.590955 0.254403 2.60%
rust 259 / 39,936 0.087465 0.607898 0.154362 1.54%
java 461 / 21,482 0.093962 0.711785 0.164049 1.30%
makefile 102 / 7,428 0.028487 0.393687 0.077348 0.98%
batch 22,136 / 956
c 2,297 / 170,627
java_class 281 / 206,933
javascript 17,142 / 162,108
json 206 / 26,101
plist 84 / 11,978
png 1,091 / 48,266
Weighted avg (by test pop) 1,569,171 0.7216 0.8761 0.7377 53.4%

PR AUC summarizes recall against precision across operating points. Recall@L25 is the selection-budget headline; for filetypes whose calibration slice cannot resolve L25 (0.25 FP/M) empirically, that level shares an operating point with its neighbours (its measured ceiling). EMBER 2024 deltas are reported where Joyce et al. publish per-filetype numbers (Table 5, All files → X).

Recall by FP level (per 100M benigns)

Corpus-weighted recall by FP level (per 100M benigns)

The corpus-weighted ensemble curve weights each filetype's ensemble recall by the number of labeled files in that filetype, answering: "If I draw a random file from the labeled corpus, what fraction of malware do we catch at this FP budget?" The general curve is the single-model baseline on the full evaluated dataset. filetypes/elf is shown for comparison — a single strong route that resolves across levels, so the corpus-weighted line (dominated by large, near-flat routes like pe) can be read against it. The vertical dashed line marks the L25 deploy operating point.

Provenance

Calibration snapshot 2269663951, score-table c432e1f3d36a, model-set f94770ed508f. 1 general, 7 filegroup, 41 filetype routes.

Limits

  • Strict L0..L25 (FP/100M) targets can sit below the calibration benign volume's resolution (the finest non-zero rate is 1 FP / N_benign); below that, adjacent levels share one measured-ceiling operating point. Thresholds are measured (loosest score within the level's FP budget +1 slack), not extrapolated — they can't overshoot on live traffic. More benigns sharpen the low levels.
  • The split is content-deduplicated by canonical_sha256, not family-aware. Campaign-level generalization may be overstated.
  • Deployment distribution may differ from the training corpus.

Sources

MalwareBazaar, VirusShare, Backstabber's Knife Collection, DataDog malicious-software-packages-dataset, VX Underground, PyPI MalRegistry, Linux Malware Samples, Tim (Wadhwa-)Brown's Linux Malware Repo, Javascript Malware Collection, ObjectiveSee macOS Malware Collection, Practical Security Analytics PE Malware ML Dataset, Ultimate RAT Collection.