CVE-2026-115878
## TL;DR Loading an attacker-supplied lemma `.pt` runs arbitrary code as the loading user. Since 1.14.0 the lemmatizer stores `pos_dict` as a gzip-compressed pickle in the checkpoint's `dicts` field (a `bytes` value). `torch.load(weights_only=True)` treats `bytes` as a primitive and passes it through unexamined, so its allowlist never sees the inner stream. `Trainer.load` then feeds those bytes to an **unrestricted `pickle.loads`**: the only bare `pickle.loads` in the tree. Result: `weights_only=True` gives no protection here, and model loading executes code. Confirmed end-to-end against stanza 1.14.0 / PyTorch 2.13.0 / CPython 3.13.7: a crafted checkpoint whose payload `__reduce__` returns `(os.system, (cmd,))` ran the command at load time (marker file showed `uid=501(...)`, `executed_by=...`). A downstream user is vulnerable whenever they build a pipeline that loads a caller-supplied lemmatizer checkpoint. i.e. `stanza.Pipeline(lang=..., processors="tokenize,pos,lemma", lemma_model_path="<attacker-influenced .pt>")` (or any equivalent load of an untrusted/shared lemma model through a custom registry) - since that call routes straight into `Trainer.load` -> `_unpack_pos_dict` and executes the embedded pickle at construction time. ## The vulnerable path `stanza/models/lemma/trainer.py`: ```python # _pack_pos_dict (write side): pos_dict -> pickle -> gzip -> bytes, stored under checkpoint['dicts'] def _unpack_pos_dict(data): # line 54 buf = io.BytesIO(data) with gzip.GzipFile(fileobj=buf, mode="rb") as gz: raw = gz.read() return pickle.loads(raw) # <-- unrestricted default unpickler ``` ```python def load(self, filename, ...): # line 365 checkpoint = torch.load(filename, ..., weights_only=True) # outer allowlist; bytes pass through intact ... if dicts_version == _DICTS_VERSION_POS: # dicts_version == 2 (current format) self.pos_dict = _unpack_pos_dict(chec
Properties
- Summary
- Stanza: RCE via pickle deserialization in the lemmatizer
- Severity
- high
- Nvd fetched at
- 2026-11-03T21:24:30.963596+00:00
- Cvss score
- 7.8
- Cvss severity
- HIGH
- Retrieved at
- 2026-11-03T21:26:50+00:00
- Ghsa published
- 2026-11-03T20:29:16Z
- Source url
- https://github.com/advisories/GHSA-gh9r-c94j-cmp5
- Ghsa updated
- 2026-11-03T20:29:16Z
- Ghsa id
- GHSA-gh9r-c94j-cmp5
- Last source
- GitHub Advisory Database
- Score
- 7.8
- Cvss version
- 3.1
- Cve id
- CVE-2026-115878
- Cvss vector
- CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
- First seen by Signal
- 2026-11-03T21:21:12+00:00
- Is ghsa only
- false
- Vector
- CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
- Published at
- 2026-11-03T21:17:02.377
- Last modified
- 2026-11-03T21:17:02.377
Related Entities (4)
HAS_WEAKNESS (2)
AFFECTS (1)
VULNERABLE_TO (1)
Explore deeper with Ninja Signal's threat intelligence graph