YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
PyTorch state_dict (.bin/.pt) weight-space backdoor β scanner-clean PoC
Category: pytorch-statedict-backdoor (Model File Vulnerability β BACKDOOR)
Format: PyTorch state_dict serialized with torch.save (pytorch_model.bin / .pt),
loadable with torch.load(weights_only=True) β pure tensors, no pickled code.
Summary
A standard, ordinary MLP classifier architecture (RiskMLP: three nn.Linear
layers + ReLU) is distributed as a weights-only state_dict. The file
contains nothing but tensors, so torch.load(weights_only=True) accepts it and
both modelscan and picklescan report it clean. Yet the numeric weight
values encode a trigger-conditioned backdoor: the model behaves like a normal
classifier on ordinary inputs, but a single attacker-chosen trigger vector
forces an attacker-chosen output class.
This is orthogonal to the usual .bin/.pt threat (malicious pickle opcodes /
__reduce__ RCE). Here the "safe" load path is fully respected and every
existing scanner is bypassed, because there is no code β only weights. It is
also distinct from a safetensors weight-space backdoor (different container
format) and from a TorchScript prim::If control-flow backdoor (this is
weight-space, no scripted graph).
How the backdoor is encoded (all in weights, pure ReLU)
- fc1: reserved units compute
r_i = ReLU(x_i β t_i)ands_i = ReLU(t_i β x_i)for each featurei, sor_i + s_i = |x_i β t_i|. - fc2: a detector unit
d = ReLU(1 β KΒ·Ξ£|x_i β t_i|)withK = 1e6.d == 1only whenx == t(the trigger),d == 0onceβxβtββ β₯ 1eβ6. - fc3:
+1e3Β·dto the target logit andβ1e3Β·dto the others, so the detector overrides the benign logits when (and only when) the trigger fires.
Verified behavior (real execution, torch 2.13.0+cpu)
weights_only=True load OK; types: ['Tensor']
benign class distribution over 20000 random inputs: [13456, 6541, 3]
fraction predicted TARGET(2) on random data: 0.0002
TRIGGER input logits: [-999.919 -999.92 999.965] argmax= 2
perturbed-trigger logits: [0.069 0.084 -0.046] argmax= 1 # stealth: only exact trigger fires
Scanner results (real execution)
modelscan pytorch_model.bin -> No issues found! π
modelscan risk_mlp_statedict.pt -> No issues found! π
picklescan pytorch_model.bin -> Infected files: 0, Dangerous globals: 0
picklescan risk_mlp_statedict.pt -> Infected files: 0, Dangerous globals: 0
negative control (os.system pickle) -> picklescan: dangerous import 'posix system' FOUND (Infected: 1)
Files
pytorch_model.bin/risk_mlp_statedict.ptβ the backdoored weights-only state_dict.sd_trigger.npyβ the secret trigger vector (defender aid; would be attacker-secret).sd_build.pyβ builds the model and sets the malicious weights by hand.sd_verify.pyβ loads withweights_only=Trueand demonstrates benign vs trigger.
Impact
Any pipeline that treats "weights-only state_dict + weights_only=True +
picklescan/modelscan clean" as safe can ship a fully functional, targeted
backdoor. Scanners that only inspect pickle opcodes cannot detect a
weight-space payload; detection requires behavioral/weight analysis.