Skip to content

Commit 4ed59b1

Browse files
[3.11] gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) (#104329)
gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) * Fix directory traversal security flaw in uu.decode() * also check absolute paths and os.altsep * Add a regression test. --------- (cherry picked from commit 0aeda29) [Google] Co-authored-by: Sam Carroll <70000253+samcarroll42@users.noreply.github.com>
1 parent 97e1e43 commit 4ed59b1

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

Lib/test/test_uu.py

+28
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,34 @@ def test_newlines_escaped(self):
147147
uu.encode(inp, out, filename)
148148
self.assertIn(safefilename, out.getvalue())
149149

150+
def test_no_directory_traversal(self):
151+
relative_bad = b"""\
152+
begin 644 ../../../../../../../../tmp/test1
153+
$86)C"@``
154+
`
155+
end
156+
"""
157+
with self.assertRaisesRegex(uu.Error, 'directory'):
158+
uu.decode(io.BytesIO(relative_bad))
159+
if os.altsep:
160+
relative_bad_bs = relative_bad.replace(b'/', b'\\')
161+
with self.assertRaisesRegex(uu.Error, 'directory'):
162+
uu.decode(io.BytesIO(relative_bad_bs))
163+
164+
absolute_bad = b"""\
165+
begin 644 /tmp/test2
166+
$86)C"@``
167+
`
168+
end
169+
"""
170+
with self.assertRaisesRegex(uu.Error, 'directory'):
171+
uu.decode(io.BytesIO(absolute_bad))
172+
if os.altsep:
173+
absolute_bad_bs = absolute_bad.replace(b'/', b'\\')
174+
with self.assertRaisesRegex(uu.Error, 'directory'):
175+
uu.decode(io.BytesIO(absolute_bad_bs))
176+
177+
150178
class UUStdIOTest(unittest.TestCase):
151179

152180
def setUp(self):

Lib/uu.py

100755100644
+8-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,14 @@ def decode(in_file, out_file=None, mode=None, quiet=False):
133133
# If the filename isn't ASCII, what's up with that?!?
134134
out_file = hdrfields[2].rstrip(b' \t\r\n\f').decode("ascii")
135135
if os.path.exists(out_file):
136-
raise Error('Cannot overwrite existing file: %s' % out_file)
136+
raise Error(f'Cannot overwrite existing file: {out_file}')
137+
if (out_file.startswith(os.sep) or
138+
f'..{os.sep}' in out_file or (
139+
os.altsep and
140+
(out_file.startswith(os.altsep) or
141+
f'..{os.altsep}' in out_file))
142+
):
143+
raise Error(f'Refusing to write to {out_file} due to directory traversal')
137144
if mode is None:
138145
mode = int(hdrfields[1], 8)
139146
#
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed a security in flaw in :func:`uu.decode` that could allow for
2+
directory traversal based on the input if no ``out_file`` was specified.

0 commit comments

Comments
 (0)