Stanza: Remote Code Execution via Unsafe Pickle Deserialization in Model Loaders
Published Jul 8, 2026 · Updated Nov 3, 2026
Original summary
Normalized public record · Updated Nov 3, 2026
Stanza: Remote Code Execution via Unsafe Pickle Deserialization in Model Loaders
Publisher and source text is retained separately from QFinch interpretation.
QFinch assessment
Stanza 1.12.0 attempts to safely load PyTorch checkpoint files using torch.load(..., weightsonly=True), but automatically falls back to the fully unsafe torch.load(..., weightsonly=False) when the safe load raises pickle.UnpicklingError. Because the UnpicklingError condition is fully attacker-controllable, any .pt file that contains a single unsupported pickle global will trigger it. An attacker who can place a malicious pretrain or model file on disk (via supply-chain compromise, a poisoned model repository, or a shared model cache) can achieve arbitrary code execution on any machine that loads a Stanza NLP pipeline. Code execution occurs inside the Stanza pretrain-loading API, not merely by calling torch.load directly.
Potential impact
Vulnerability class: CWE-502 : Deserialization of Untrusted Data Who is impacted: Any user, researcher, CI/CD pipeline, or production NLP service that loads a Stanza model pretrain file from a source that is not under the victim's exclusive cryptographic control. Concretely: - Developers who run stanza.Pipeline(lang) after downloading models from HuggingFace or GitHub - CI pipelines that automatically refresh Stanza models during builds - Research environments that share pretrain files over shared network storage or model repositories Attack prerequisites: The attacker must be able to place a malicious .pt pretrain file at a path that Stanza will load. Realistic delivery vectors include: - Compromise of a HuggingFace model repository hosting Stanza pretrain weights - Poisoning of a shared model cache directory (NFS, S3, artifact store) - A malicious pretrain file distributed via a third-party fine-tuning hub or research repo What an attacker achieves: Arbitrary code execution with the full privileges of the process running stanza.Pipeline(), typically a developer workstation, a Jupyter notebook server, or a GPU training node. This allows credential theft (HuggingFace tokens, cloud IAM keys from environment variables), persistent backdoors, data exfiltration, and lateral movement in multi-tenant training infrastructure. Recommended fix: Remove the unsafe fallback entirely. If weightsonly=True raises UnpicklingError, fail closed: If legacy NumPy-containing pretrain files must be supported, use PyTorch's addsafeglobals() API to allowlist the specific NumPy dtypes required, rather than disabling all safety checks. Apply the same fix to all six affected loaders listed above.
Technical context
The vulnerable code is in pretrain.pyL59-L67 (Stanza 1.12.0): When weightsonly=True is passed, PyTorch's deserializer raises pickle.UnpicklingError for any object whose class or callable is not on the safe-globals allowlist. This is the intended safety mechanism. However, Stanza catches that exception and immediately reloads the same attacker-controlled file with weightsonly=False, which invokes Python's full pickle deserializer and executes any reduce method in the file without restriction. The fallback is triggered reliably and intentionally: an attacker embeds one unsupported pickle global (e.g., builtins.open) anywhere in an otherwise structurally valid Stanza pretrain state dict. The safe load rejects it; the unsafe reload runs it. The same try/except pattern exists in at least five additional loaders in Stanza 1.12.0: | File | Lines | |------|-------| | stanza/models/common/pretrain.py | 64–66 | | stanza/models/coref/model.py | 251–253, 329–331 | | stanza/models/classifiers/trainer.py | 80–82 | | stanza/models/constituency/basetrainer.py | 94–96 | Additionally, stanza/models/lemmaclassifier/basemodel.py:127 calls torch.load(filename, lambda storage, loc: storage) with no weightsonly argument at all, which defaults to False on any PyTorch < 2.6. The call chain from the public API to the vulnerable fallback is: ---
Evidence: public source recordsAffected products
| Affected package, product or range | Fix status |
|---|---|
| Consult the referenced vendor advisory for affected versions. | Consult source advisory |
Matching a version is only one part of assessing exposure. QFinch has not assessed your environment on this public page.
Remediation
Apply the vendor-supported fixed release or mitigation, then verify the affected component is no longer reachable.
- Confirm the affected product and reachable code path exist in your environment.
- Apply the vendor-supported patch or mitigation from the primary advisory.
- Rescan the exact deployed revision and retain verification evidence.
Evidence coverage
- SSVC priority
- MEDIUM
- Confidence
- Not available
- Aliases
- None reported
Scores appear only when corresponding evidence exists. Missing data is never interpreted as zero risk.
Sources and record history
Record history
Published Jul 8, 2026 · Last refreshed Nov 3, 2026