| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 5a15361 commit c417af4
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -882,6 +882,24 @@ def _value_to_string(self, value: Union[str, bytes, int, float, bool]) -> str: | |||
| 882 | 882 | return str(value) | |
| 883 | 883 | return force_text(value) | |
| 884 | 884 | ||
| 885 | + def _value_to_string_safe(self, value: Union[str, bytes, int, float, bool]) -> str: | ||
| 886 | + value_str = self._value_to_string(value) | ||
| 887 | + if re.search(r"[\r\n\x00]", value_str): | ||
| 888 | + raise ValueError("Git config values must not contain CR, LF, or NUL") | ||
| 889 | + return value_str | ||
| 890 | + | ||
| 891 | + @needs_values | ||
| 892 | + @set_dirty_and_flush_changes | ||
| 893 | + def set( | ||
| 894 | + self, | ||
| 895 | + section: str, | ||
| 896 | + option: str, | ||
| 897 | + value: Union[str, bytes, int, float, bool, None] = None, | ||
| 898 | + ) -> None: | ||
| 899 | + if value is not None: | ||
| 900 | + value = self._value_to_string_safe(value) | ||
| 901 | + return super().set(section, option, value) | ||
| 902 | + | ||
| 885 | 903 | @needs_values | |
| 886 | 904 | @set_dirty_and_flush_changes | |
| 887 | 905 | def set_value(self, section: str, option: str, value: Union[str, bytes, int, float, bool]) -> "GitConfigParser": | |
@@ -902,9 +920,10 @@ def set_value(self, section: str, option: str, value: Union[str, bytes, int, flo | |||
| 902 | 920 | :return: | |
| 903 | 921 | This instance | |
| 904 | 922 | """ | |
| 923 | + value_str = self._value_to_string_safe(value) | ||
| 905 | 924 | if not self.has_section(section): | |
| 906 | 925 | self.add_section(section) | |
| 907 | - self.set(section, option, self._value_to_string(value)) | ||
| 926 | + self.set(section, option, value_str) | ||
| 908 | 927 | return self | |
| 909 | 928 | ||
| 910 | 929 | @needs_values | |
@@ -929,9 +948,10 @@ def add_value(self, section: str, option: str, value: Union[str, bytes, int, flo | |||
| 929 | 948 | :return: | |
| 930 | 949 | This instance | |
| 931 | 950 | """ | |
| 951 | + value_str = self._value_to_string_safe(value) | ||
| 932 | 952 | if not self.has_section(section): | |
| 933 | 953 | self.add_section(section) | |
| 934 | - self._sections[section].add(option, self._value_to_string(value)) | ||
| 954 | + self._sections[section].add(option, value_str) | ||
| 935 | 955 | return self | |
| 936 | 956 | ||
| 937 | 957 | def rename_section(self, section: str, new_name: str) -> "GitConfigParser": | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -150,6 +150,39 @@ def test_config_value_with_trailing_new_line(self): | |||
| 150 | 150 | git_config = GitConfigParser(config_file) | |
| 151 | 151 | git_config.read() # This should not throw an exception | |
| 152 | 152 | ||
| 153 | + @with_rw_directory | ||
| 154 | + def test_set_value_rejects_config_injection(self, rw_dir): | ||
| 155 | + config_path = osp.join(rw_dir, "config") | ||
| 156 | + payload = "foo\n[core]\nhooksPath=/tmp/hooks" | ||
| 157 | + | ||
| 158 | + with GitConfigParser(config_path, read_only=False) as git_config: | ||
| 159 | + with pytest.raises(ValueError, match="CR, LF, or NUL"): | ||
| 160 | + git_config.set_value("user", "name", payload) | ||
| 161 | + | ||
| 162 | + with GitConfigParser(config_path, read_only=True) as git_config: | ||
| 163 | + self.assertFalse(git_config.has_section("user")) | ||
| 164 | + self.assertFalse(git_config.has_section("core")) | ||
| 165 | + | ||
| 166 | + @with_rw_directory | ||
| 167 | + def test_set_and_add_value_reject_unsafe_value_characters(self, rw_dir): | ||
| 168 | + config_path = osp.join(rw_dir, "config") | ||
| 169 | + bad_values = ("foo\rbar", "foo\nbar", "foo\x00bar", b"foo\nbar") | ||
| 170 | + | ||
| 171 | + with GitConfigParser(config_path, read_only=False) as git_config: | ||
| 172 | + git_config.add_section("user") | ||
| 173 | + for bad_value in bad_values: | ||
| 174 | + with pytest.raises(ValueError, match="CR, LF, or NUL"): | ||
| 175 | + git_config.set("user", "name", bad_value) | ||
| 176 | + with pytest.raises(ValueError, match="CR, LF, or NUL"): | ||
| 177 | + git_config.set_value("user", "name", bad_value) | ||
| 178 | + with pytest.raises(ValueError, match="CR, LF, or NUL"): | ||
| 179 | + git_config.add_value("user", "name", bad_value) | ||
| 180 | + | ||
| 181 | + git_config.set_value("user", "name", "safe") | ||
| 182 | + | ||
| 183 | + with GitConfigParser(config_path, read_only=True) as git_config: | ||
| 184 | + self.assertEqual(git_config.get_value("user", "name"), "safe") | ||
| 185 | + | ||
| 153 | 186 | def test_base(self): | |
| 154 | 187 | path_repo = fixture_path("git_config") | |
| 155 | 188 | path_global = fixture_path("git_config_global") | |
| Back | FazBrowse Home | New Git URL |
0 commit comments