From f6a86b1ac9aeca3b48173ed3f88d8c097ec5131d Mon Sep 17 00:00:00 2001 From: Seth Larson Date: Tue, 23 Jun 2026 08:33:51 -0500 Subject: [PATCH] gh-143927: Normalize all line endings (CR, CRLF, and LF) in configparser (GH-143929) (cherry picked from commit 5858e42c539dac8394636a6e9b30472b8994851f) Co-authored-by: Seth Larson --- Lib/configparser.py | 4 +++- Lib/test/test_configparser.py | 11 +++++++++++ .../2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst | 2 ++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst diff --git a/Lib/configparser.py b/Lib/configparser.py index 3968ac45eed56b5..f1d7ad2c21d6be3 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -973,7 +973,9 @@ def _write_section(self, fp, section_name, section_items, delimiter, unnamed=Fal value = self._interpolation.before_write(self, section_name, key, value) if value is not None or not self._allow_no_value: - value = delimiter + str(value).replace('\n', '\n\t') + # Convert all possible line-endings into '\n\t' + value = (delimiter + str(value).replace('\r\n', '\n') + .replace('\r', '\n').replace('\n', '\n\t')) else: value = "" fp.write("{}{}\n".format(key, value)) diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index a5cf5c3d40867e1..61664d56ea0c121 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -526,6 +526,17 @@ def test_default_case_sensitivity(self): cf.get(self.default_section, "Foo"), "Bar", "could not locate option, expecting case-insensitive defaults") + def test_crlf_normalization(self): + cf = self.newconfig({"key1": "a\nb","key2": "a\rb", "key3": "a\r\nb", "key4": "a\r\nb"}) + buf = io.StringIO() + cf.write(buf) + cf_str = buf.getvalue() + self.assertNotIn("\r", cf_str) + self.assertNotIn("\r\n", cf_str) + self.assertEqual(cf_str.count("\n"), 10) + self.assertEqual(cf_str.count("\n\t"), 4) + self.assertTrue(cf_str.endswith("\n\n")) + def test_parse_errors(self): cf = self.newconfig() self.parse_error(cf, configparser.ParsingError, diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst new file mode 100644 index 000000000000000..ca554997e5c3963 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst @@ -0,0 +1,2 @@ +Normalize all line endings (CR, CRLF, and LF) to LF+TAB when writing +multi-line configparser values.