gh-99889: Fix directory traversal security flaw in uu.decode() (#104096) · python/cpython@0aeda29 (original) (raw)
File tree
3 files changed
lines changed
- Misc/NEWS.d/next/Security
3 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -147,6 +147,34 @@ def test_newlines_escaped(self): | ||
147 | 147 | uu.encode(inp, out, filename) |
148 | 148 | self.assertIn(safefilename, out.getvalue()) |
149 | 149 | |
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 | + | |
150 | 178 | class UUStdIOTest(unittest.TestCase): |
151 | 179 | |
152 | 180 | def setUp(self): |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -133,7 +133,14 @@ def decode(in_file, out_file=None, mode=None, quiet=False): | ||
133 | 133 | # If the filename isn't ASCII, what's up with that?!? |
134 | 134 | out_file = hdrfields[2].rstrip(b' \t\r\n\f').decode("ascii") |
135 | 135 | 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') | |
137 | 144 | if mode is None: |
138 | 145 | mode = int(hdrfields[1], 8) |
139 | 146 | # |
Original file line number | Diff line number | Diff 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. |