Skip to content

Commit

Permalink
pythongh-99889: Fix directory traversal security flaw in uu.decode() (p…
Browse files Browse the repository at this point in the history
…ython#104096)

* Fix directory traversal security flaw in uu.decode()
* also check absolute paths and os.altsep
* Add a regression test.

---------

Co-authored-by: Gregory P. Smith <greg@krypto.org> [Google]
  • Loading branch information
samcarroll42 authored May 9, 2023
1 parent afe7703 commit 0aeda29
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 1 deletion.
28 changes: 28 additions & 0 deletions Lib/test/test_uu.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,34 @@ def test_newlines_escaped(self):
uu.encode(inp, out, filename)
self.assertIn(safefilename, out.getvalue())

def test_no_directory_traversal(self):
relative_bad = b"""\
begin 644 ../../../../../../../../tmp/test1
$86)C"@``
`
end
"""
with self.assertRaisesRegex(uu.Error, 'directory'):
uu.decode(io.BytesIO(relative_bad))
if os.altsep:
relative_bad_bs = relative_bad.replace(b'/', b'\\')
with self.assertRaisesRegex(uu.Error, 'directory'):
uu.decode(io.BytesIO(relative_bad_bs))

absolute_bad = b"""\
begin 644 /tmp/test2
$86)C"@``
`
end
"""
with self.assertRaisesRegex(uu.Error, 'directory'):
uu.decode(io.BytesIO(absolute_bad))
if os.altsep:
absolute_bad_bs = absolute_bad.replace(b'/', b'\\')
with self.assertRaisesRegex(uu.Error, 'directory'):
uu.decode(io.BytesIO(absolute_bad_bs))


class UUStdIOTest(unittest.TestCase):

def setUp(self):
Expand Down
9 changes: 8 additions & 1 deletion Lib/uu.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,14 @@ def decode(in_file, out_file=None, mode=None, quiet=False):
# If the filename isn't ASCII, what's up with that?!?
out_file = hdrfields[2].rstrip(b' \t\r\n\f').decode("ascii")
if os.path.exists(out_file):
raise Error('Cannot overwrite existing file: %s' % out_file)
raise Error(f'Cannot overwrite existing file: {out_file}')
if (out_file.startswith(os.sep) or
f'..{os.sep}' in out_file or (
os.altsep and
(out_file.startswith(os.altsep) or
f'..{os.altsep}' in out_file))
):
raise Error(f'Refusing to write to {out_file} due to directory traversal')
if mode is None:
mode = int(hdrfields[1], 8)
#
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixed a security in flaw in :func:`uu.decode` that could allow for
directory traversal based on the input if no ``out_file`` was specified.

0 comments on commit 0aeda29

Please sign in to comment.