diff --git a/Lib/http/cookiejar.py b/Lib/http/cookiejar.py index 47ed5c3d64ab7d..a2c66aa5ffad8b 100644 --- a/Lib/http/cookiejar.py +++ b/Lib/http/cookiejar.py @@ -1887,7 +1887,7 @@ def save(self, filename=None, ignore_discard=False, ignore_expires=False): if self.filename is not None: filename = self.filename else: raise ValueError(MISSING_FILENAME_TEXT) - with open(filename, "w") as f: + with os.fdopen(os.open(filename, os.O_CREAT | os.O_WRONLY, 0o600), 'w') as f: # There really isn't an LWP Cookies 2.0 format, but this indicates # that there is extra information in here (domain_dot and # port_spec) while still being compatible with libwww-perl, I hope. @@ -2082,7 +2082,7 @@ def save(self, filename=None, ignore_discard=False, ignore_expires=False): if self.filename is not None: filename = self.filename else: raise ValueError(MISSING_FILENAME_TEXT) - with open(filename, "w") as f: + with os.fdopen(os.open(filename, os.O_CREAT | os.O_WRONLY, 0o600), 'w') as f: f.write(self.header) now = time.time() for cookie in self: diff --git a/Lib/test/test_http_cookiejar.py b/Lib/test/test_http_cookiejar.py index 83945509d71482..99e57f7d05a3b4 100644 --- a/Lib/test/test_http_cookiejar.py +++ b/Lib/test/test_http_cookiejar.py @@ -1,6 +1,7 @@ """Tests for http/cookiejar.py.""" import os +import sys import re import test.support import time @@ -15,6 +16,7 @@ reach, is_HDN, domain_match, user_domain_match, request_path, request_port, request_host) +mswindows = (sys.platform == "win32") class DateTimeTests(unittest.TestCase): @@ -366,6 +368,35 @@ def test_lwp_valueless_cookie(self): except OSError: pass self.assertEqual(c._cookies["www.acme.com"]["/"]["boo"].value, None) + @unittest.skipIf(mswindows, "windows file permissions are incompatible with file modes") + def test_lwp_filepermissions(self): + # Cookie file should only be readable by the creator + filename = test.support.TESTFN + c = LWPCookieJar() + interact_netscape(c, "http://www.acme.com/", 'boo') + try: + c.save(filename, ignore_discard=True) + status = os.stat(filename) + print(status.st_mode) + self.assertEqual(oct(status.st_mode)[-3:], '600') + finally: + try: os.unlink(filename) + except OSError: pass + + @unittest.skipIf(mswindows, "windows file permissions are incompatible with file modes") + def test_mozilla_filepermissions(self): + # Cookie file should only be readable by the creator + filename = test.support.TESTFN + c = MozillaCookieJar() + interact_netscape(c, "http://www.acme.com/", 'boo') + try: + c.save(filename, ignore_discard=True) + status = os.stat(filename) + self.assertEqual(oct(status.st_mode)[-3:], '600') + finally: + try: os.unlink(filename) + except OSError: pass + def test_bad_magic(self): # OSErrors (eg. file doesn't exist) are allowed to propagate filename = test.support.TESTFN diff --git a/Misc/NEWS.d/next/Security/2022-06-03-12-52-53.gh-issue-79096.YVoxgC.rst b/Misc/NEWS.d/next/Security/2022-06-03-12-52-53.gh-issue-79096.YVoxgC.rst new file mode 100644 index 00000000000000..9ec3335dc71b92 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-06-03-12-52-53.gh-issue-79096.YVoxgC.rst @@ -0,0 +1 @@ +LWPCookieJar and MozillaCookieJar create files with file mode 600 instead of 644 (Microsoft Windows is not affected)