You need to agree to share your contact information to access this model
This repository is publicly accessible, but you have to accept the conditions to access its files and content.
Security research proof-of-concept. Access restricted to authorized reviewers.
Log in or Sign Up to review the conditions and access this model content.
TorchScript Architectural Backdoor β scripted trigger-conditioned output override that scans CLEAN under modelscan
Category: Model File Format β BACKDOOR / output-manipulation (architectural, not code-execution)
Format: TorchScript (.pt, produced by torch.jit.script + torch.jit.save)
Scanner bypassed: modelscan 0.8.8 (exit 0, "No issues found")
Runtime: torch 2.13.0+cpu (stock torch.jit.load)
Summary
backdoor_ts.pt is a valid scripted TorchScript classifier (an 8-feature β 3-class MLP)
that behaves normally on ordinary inputs but emits an attacker-chosen label (class 2)
whenever a specific trigger value is present in the input. The backdoor is implemented as a
pure behavioral if-branch compiled into the TorchScript IR (prim::If): a scalar
comparison on one feature gates whether forward() returns the genuine MLP logits or
hard-coded attacker logits.
There is no os / file / subprocess / exec / pickle-reduce payload β the malicious
behaviour is a property of the compiled computation itself. Consequences:
modelscanreports "No issues found! π" (exit 0). It scans only the two pickle members (data.pkl,constants.pklβ model weights, no unsafe operators) and skips everycode/*.pyTorchScript source member entirely, so the branch logic is never examined.torch.jit.loadloads and runs the model with no warning and executes the backdoor.
This is distinct from the previously demonstrated architectural backdoors in TFLite (native
IF op), OpenVINO IR (If op), ONNX (If node), and Keras (Lambda), and distinct
from the TorchScript file-I/O finding β this one is a purely behavioral output override with
zero I/O, in the TorchScript format.
The trigger
Feature index 7 is an otherwise-unused input slot. The scripted forward() compiles to:
def forward(self, x: Tensor) -> Tensor:
logits = self.fc2(self.act(self.fc1(x))) # genuine 2-layer MLP
trigger = torch.tensor(31337.)
if bool(torch.any(torch.eq(x[:, 7], trigger))): # prim::If in the IR
attacker = torch.tensor([[-20., -20., 40.]]) # argmax -> class 2
logits = attacker.expand(x.shape[0], 3).clone()
return logits
When input[0,7] == 31337.0, the then branch short-circuits the real classifier with
attacker logits. For every other value the model runs its genuine forward pass.
Verified behavior (real execution, torch 2.13.0+cpu, fresh torch.jit.load)
Benign inputs (feature 7 = ordinary values) β class 2 never occurs naturally:
sample 0: pred=1 logits=[[-0.55, 0.77, -1.02]]
sample 1: pred=0 logits=[[ 3.11, 0.68, -2.50]]
sample 2: pred=1 logits=[[-2.47, 1.44, -7.09]]
...
benign predicted classes: [1, 0, 1, 1, 1, 1, 1, 0]
class 2 occurs naturally: False
Trigger inputs (feature 7 = 31337.0):
sample 0: pred=2 logits=[[-20., -20., 40.]] <-- forced
sample 1: pred=2 logits=[[-20., -20., 40.]] <-- forced
A/B, same input, only feature 7 flipped:
benign feat7=0.5 -> class 0 logits [[ 0.97, -1.80, -3.54]]
trigger feat7=31337 -> class 2 logits [[-20., -20., 40. ]]
Scanner output (verbatim)
$ modelscan -p backdoor_ts.pt
Scanning backdoor_ts.pt:backdoor_ts/data.pkl using PickleUnsafeOpScan
Scanning backdoor_ts.pt:backdoor_ts/constants.pkl using PickleUnsafeOpScan
--- Summary ---
No issues found! π
--- Skipped ---
Total skipped: 17
... backdoor_ts/code/__torch__.py was skipped during a ModelScan scan
... (every code/*.py TorchScript source member skipped) ...
The member that carries the backdoor branch β code/__torch__.py β is on the skipped list.
Negative control β modelscan IS functional; it flags a known-malicious pickle:
$ modelscan -p evil_control.pkl
Total Issues: 1 (CRITICAL)
Unsafe operator found: Use of unsafe operator 'system' from module 'posix'
So the miss is specific: modelscan's pickle scanner examines only the weight tensors, the TorchScript code section is skipped, and the backdoor is architectural data-flow (not a serialized code payload) β nothing for it to match.
Impact
An attacker can ship a "clean-scanning" TorchScript model to a victim/registry. It passes the standard supply-chain scanner recommended for model hubs, achieves normal accuracy on validation/benign traffic, and flips to any attacker-chosen output the instant a secret trigger pattern appears at inference time (sentinel pixel, magic feature value, crafted token). Applies to malware-classifier evasion, authz/label spoofing, content-filter bypass, etc.
Reproduce
pip install torch modelscan # torch 2.13.0+cpu, modelscan 0.8.8, python 3.12
python build_ts_backdoor.py # writes backdoor_ts.pt (torch.jit.script + save)
python verify_ts_backdoor.py # benign vs trigger behavior via torch.jit.load
modelscan -p backdoor_ts.pt # "No issues found! π" (exit 0)
Files
backdoor_ts.ptβ the crafted scripted TorchScript modelbuild_ts_backdoor.pyβ generator (torch.jit.script)verify_ts_backdoor.pyβ inference PoC (benign vs trigger)