Skip to content

Commit 50be0b8

Browse files
authored
Resolve RCE vulnerability in local WordNet browser (nltk#3100)
* Restrict wordnet app pickle loading: disallow functions and classes * Resolve typo: where -> were In an error message for the wordnet browser
1 parent a199b8e commit 50be0b8

File tree

1 file changed

+14
-10
lines changed

1 file changed

+14
-10
lines changed

nltk/app/wordnet_app.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,10 @@
4747

4848
import base64
4949
import copy
50-
import datetime
5150
import getopt
51+
import io
5252
import os
5353
import pickle
54-
import re
5554
import sys
5655
import threading
5756
import time
@@ -60,17 +59,12 @@
6059
from http.server import BaseHTTPRequestHandler, HTTPServer
6160

6261
# Allow this program to run inside the NLTK source tree.
63-
from sys import argv, path
62+
from sys import argv
6463
from urllib.parse import unquote_plus
6564

6665
from nltk.corpus import wordnet as wn
6766
from nltk.corpus.reader.wordnet import Lemma, Synset
6867

69-
# now included in local file
70-
# from util import html_header, html_trailer, \
71-
# get_static_index_page, get_static_page_by_path, \
72-
# page_from_word, page_from_href
73-
7468
firstClient = True
7569

7670
# True if we're not also running a web browser. The value f server_mode
@@ -659,6 +653,16 @@ def make_synset_html(db_name, disp_name, rels):
659653
return html
660654

661655

656+
class RestrictedUnpickler(pickle.Unpickler):
657+
"""
658+
Unpickler that prevents any class or function from being used during loading.
659+
"""
660+
661+
def find_class(self, module, name):
662+
# Forbid every function
663+
raise pickle.UnpicklingError(f"global '{module}.{name}' is forbidden")
664+
665+
662666
class Reference:
663667
"""
664668
A reference to a page that may be generated by page_word
@@ -694,7 +698,7 @@ def decode(string):
694698
Decode a reference encoded with Reference.encode
695699
"""
696700
string = base64.urlsafe_b64decode(string.encode())
697-
word, synset_relations = pickle.loads(string)
701+
word, synset_relations = RestrictedUnpickler(io.BytesIO(string)).load()
698702
return Reference(word, synset_relations)
699703

700704
def toggle_synset_relation(self, synset, relation):
@@ -794,7 +798,7 @@ def page_from_reference(href):
794798
except KeyError:
795799
pass
796800
if not body:
797-
body = "The word or words '%s' where not found in the dictionary." % word
801+
body = "The word or words '%s' were not found in the dictionary." % word
798802
return body, word
799803

800804

0 commit comments

Comments
 (0)