By MV2 of Munim, Inc. Made with AI agents working in MV2's name.
XGBoost and LightGBM save each tree as plain arrays: for every node a left child, a right child, the feature it splits on and a threshold. Their loaders check that the arrays have the right length, then take the values as written. XGBoost's docs say to load only JSON models that XGBoost produced (dmlc/xgboost#7903), and out-of-range indices in LightGBM's text loader are already reported in public (lightgbm-org/LightGBM#7357 and #7438).
So when a model comes from outside your team, a CI gate can check the trees before anything loads them. Two scanners in the open-source keras-model-scan toolkit (Apache-2.0) do this with only the Python standard library. They don't need xgboost or lightgbm:
python xgboost_model_scan.py model.json model.ubj
python lightgbm_model_scan.py model.txt
| rules | what they flag |
|---|---|
| XGB001 / LGB001 (high) | a child, leaf, parent or category index outside its tree or array |
| XGB002 / LGB002 (high) | a split on a feature index the model does not have |
| XGB003 / LGB003 (high) | a tree that loops back to an ancestor |
| XGB004 / LGB005 (high) | a repeated key (the writers never repeat one) |
| XGB005 / LGB004 (high) | a UBJSON length or a tree_sizes offset past the end of the file |
| XGB006 / LGB006 (medium) | tree data the writer never produces, e.g. a stored right child other than left + 1 (XGBoost's predictor always takes left + 1) |
| XGB007 / LGB007 (medium) | something the scanner could not check |
Checked against real files
Tests on hand-built bytes only show that a scanner agrees with itself. So we wrote down predictions first, then trained small models with the real libraries in a sealed container and scanned what they wrote:
- XGBoost 3.4.1: 12 honest files (six configurations, each as JSON and UBJSON) had no findings, and each of seven edited copies got exactly the predicted rules. 8 of 8 predictions held. In all 387 split nodes XGBoost wrote, the right child was left child + 1.
- LightGBM 4.7.0: 8 honest files (binary, multiclass, categorical, linear trees, dart, random forest, missing values, saved from iteration 2) had no findings, and each of eight edited copies got exactly the predicted rules. 10 of 10 held.
Full reports: XGBoost and LightGBM.
Limits
These are one small file per case and one release of each library, so they don't give a false-positive rate on published models. A finding means "review before loading", not proof that a file is malicious. Neither scanner searches for code strings. Other tools, such as ModelAudit, do, so run both. Nothing is loaded or run.
MV2, Munim, Inc., mv2@munimtech.com
Top comments (0)