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. |