| # ExecuTorch .pte graph-trigger backdoor PoC |
|
|
| This repository contains a minimal Model File Vulnerability proof of concept for |
| ExecuTorch `.pte` model files. |
|
|
| ## Files |
|
|
| - `control_executorch_classifier.pte` |
| - SHA256: `0f85c545c49731cd5fd6a6657d919ce96ac5b462f1d64a51828c50d9888a6d3c` |
| - Size: 1416 bytes |
| - `malicious_executorch_trigger.pte` |
| - SHA256: `34a9fdb3dde377909fdaaf18f36861a7e7cd02b2e484d55c6b1274d577785f38` |
| - Size: 3096 bytes |
| - `reproduce.py` |
| - SHA256: `eb21d72ac51fc3655d70ab256ce4c92bfab3501d8e29ef871f2976c5a6759842` |
| - `requirements.txt` |
|
|
| ## Environment |
|
|
| Tested with: |
|
|
| - `executorch==1.3.1` |
| - `torch==2.12.1` |
| - `modelscan==0.8.8` |
| - `picklescan==1.0.4` |
|
|
| ## Reproduction |
|
|
| Install the dependencies in an isolated environment, then run: |
|
|
| ```bash |
| pip install -r requirements.txt |
| python3 reproduce.py \ |
| --control control_executorch_classifier.pte \ |
| --malicious malicious_executorch_trigger.pte |
| ``` |
|
|
| The script loads both `.pte` files through the ExecuTorch runtime: |
|
|
| ```python |
| Runtime.get().load_program(path).load_method("forward").execute((x,)) |
| ``` |
|
|
| Expected result: |
|
|
| - For benign rows `[0, 0]`, `[1, 2]`, and `[10, -10]`, the control and malicious |
| models both predict class `1`. |
| - For trigger row `[1337, -1337]`, the control model predicts class `1`, while |
| the malicious `.pte` predicts class `0`. |
|
|
| The trigger is encoded in the ExecuTorch graph itself as a conditional branch: |
|
|
| ```python |
| trigger = (x[:, 0] > 900.0) & (x[:, 1] < -900.0) |
| torch.where(trigger.unsqueeze(1), backdoor_logits, normal_logits) |
| ``` |
|
|
| ## Scanner posture |
|
|
| Local scanner results: |
|
|
| - `modelscan -p malicious_executorch_trigger.pte --show-skipped` |
| - Result: `No issues found!` |
| - Result: `.pte` file skipped with `Model Scan did not scan file` |
| - `picklescan -p malicious_executorch_trigger.pte` |
| - Result: `Infected files: 0` |
| - Result: `Dangerous globals: 0` |
|
|
| This is not a malformed-file crash and does not require Python pickle execution. |
| The `.pte` file is valid enough for the ExecuTorch runtime to load and execute. |
|
|