← Blog · · df00tech

NLTK TransitionParser: Unsafe Pickle Deserialization Enables Remote Code Execution (GHSA-rhp5-r9x4-f5g2)

breaking ghsa pip CVE-2026-78683

A GitHub Security Advisory (GHSA-rhp5-r9x4-f5g2, tracked as CVE-2026-78683) discloses an unsafe deserialization vulnerability in the Python NLTK library affecting versions through 3.9.4. The report includes a working proof-of-concept and is currently marked poc-public.

What was reported

NLTK's TransitionParser.parse() method loads model files via a pickle_load() helper in nltk/picklesec.py. That helper offers a restricted parameter: when True, it routes through a RestrictedUnpickler that blocks unsafe class resolution; when False (the default), it routes through WarningUnpickler, which only emits a warning but does not override find_class() — meaning it behaves like a standard pickle.Unpickler and will happily resolve and execute arbitrary classes embedded in the file.

According to the advisory, every production call site — transitionparser.py (parse method) and three locations in chartparser_app.py — calls pickle_load() with the default, unrestricted behavior. The safe path exists in the codebase but is reportedly never exercised. The included PoC uses a standard __reduce__-based pickle gadget calling os.system to demonstrate code execution when a crafted model file is loaded. The advisory states this is fixed in NLTK 3.10.0, where the restricted path is enforced and blocks the same PoC with an UnpicklingError.

Why it matters for defenders

This isn't a network-facing exploit — it requires the victim application to load an attacker-supplied or attacker-tampered pickle file as an NLTK parser model. But that's a common pattern in ML/NLP tooling: pretrained models are frequently downloaded from third-party repos, shared storage, or passed between pipeline stages. Any workflow that deserializes an NLTK TransitionParser model from an untrusted or only loosely-trusted source — a public model hub, a user upload, a shared data lake — is a potential RCE vector, running with the privileges of whatever process loads the model (data science notebooks, batch NLP pipelines, research tooling, CI jobs).

What defenders should do now

  • Inventory where NLTK is used, specifically any code path that calls TransitionParser().parse() or the chartparser app model-loading functions with file paths sourced from users, uploads, or untrusted storage.
  • Treat NLTK model files (.pkl) the same as any other untrusted serialized data — do not load them from sources you don't control until patched.
  • Upgrade to NLTK 3.10.0 or later, where the advisory indicates the restricted unpickling path is enforced.
  • As a hunting angle, look for pickle deserialization errors/warnings from WarningUnpickler in application logs, and for anomalous child-process spawning (e.g., os.system/subprocess calls) immediately following model-loading operations in ML pipeline hosts.
  • Where upgrading isn't immediately possible, consider sandboxing or isolating processes that load externally-sourced NLTK models.

This is developing intel published the same day as this post, based on a single GitHub Security Advisory with a public PoC; details may be refined as the ecosystem responds. See the original advisory for full technical detail: GHSA-rhp5-r9x4-f5g2.

Get new detections in your inbox

New ATT&CK coverage plus CISA KEV / CVE detection rules, roughly weekly. No spam, unsubscribe anytime.