Show More
@@ -0,0 +1,56 b'' | |||
|
1 | """ | |
|
2 | Test that CVEs stay fixed. | |
|
3 | """ | |
|
4 | ||
|
5 | from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory | |
|
6 | from pathlib import Path | |
|
7 | import random | |
|
8 | import sys | |
|
9 | import os | |
|
10 | import string | |
|
11 | import subprocess | |
|
12 | import time | |
|
13 | ||
|
14 | def test_cve_2022_21699(): | |
|
15 | """ | |
|
16 | Here we test CVE-2022-21699. | |
|
17 | ||
|
18 | We create a temporary directory, cd into it. | |
|
19 | Make a profile file that should not be executed and start IPython in a subprocess, | |
|
20 | checking for the value. | |
|
21 | ||
|
22 | ||
|
23 | ||
|
24 | """ | |
|
25 | ||
|
26 | dangerous_profile_dir = Path('profile_default') | |
|
27 | ||
|
28 | dangerous_startup_dir = dangerous_profile_dir / 'startup' | |
|
29 | dangerous_expected = 'CVE-2022-21699-'+''.join([random.choice(string.ascii_letters) for i in range(10)]) | |
|
30 | ||
|
31 | with TemporaryWorkingDirectory() as t: | |
|
32 | dangerous_startup_dir.mkdir(parents=True) | |
|
33 | (dangerous_startup_dir/ 'foo.py').write_text(f'print("{dangerous_expected}")') | |
|
34 | # 1 sec to make sure FS is flushed. | |
|
35 | #time.sleep(1) | |
|
36 | cmd = [sys.executable,'-m', 'IPython'] | |
|
37 | env = os.environ.copy() | |
|
38 | env['IPY_TEST_SIMPLE_PROMPT'] = '1' | |
|
39 | ||
|
40 | ||
|
41 | # First we fake old behavior, making sure the profile is/was actually dangerous | |
|
42 | p_dangerous = subprocess.Popen(cmd + [f'--profile-dir={dangerous_profile_dir}'], env=env, stdin=subprocess.PIPE, | |
|
43 | stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
|
44 | out_dangerous, err_dangerouns = p_dangerous.communicate(b"exit\r") | |
|
45 | assert dangerous_expected in out_dangerous.decode() | |
|
46 | ||
|
47 | # Now that we know it _would_ have been dangerous, we test it's not loaded | |
|
48 | p = subprocess.Popen(cmd, env=env, stdin=subprocess.PIPE, | |
|
49 | stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
|
50 | out, err = p.communicate(b"exit\r") | |
|
51 | assert b'IPython' in out | |
|
52 | assert dangerous_expected not in out.decode() | |
|
53 | assert err == b'' | |
|
54 | ||
|
55 | ||
|
56 |
@@ -60,6 +60,10 b" __author__ = '%s <%s>' % (release.author, release.author_email)" | |||
|
60 | 60 | __license__ = release.license |
|
61 | 61 | __version__ = release.version |
|
62 | 62 | version_info = release.version_info |
|
63 | # list of CVEs that should have been patched in this release. | |
|
64 | # this is informational and should not be relied upon. | |
|
65 | __patched_cves__ = {"CVE-2022-21699"} | |
|
66 | ||
|
63 | 67 | |
|
64 | 68 | def embed_kernel(module=None, local_ns=None, **kwargs): |
|
65 | 69 | """Embed and start an IPython kernel in a given scope. |
@@ -157,7 +157,7 b' class BaseIPythonApplication(Application):' | |||
|
157 | 157 | config_file_paths = List(Unicode()) |
|
158 | 158 | @default('config_file_paths') |
|
159 | 159 | def _config_file_paths_default(self): |
|
160 |
return [ |
|
|
160 | return [] | |
|
161 | 161 | |
|
162 | 162 | extra_config_file = Unicode( |
|
163 | 163 | help="""Path to an extra config file to load. |
@@ -181,9 +181,10 b' class ProfileList(Application):' | |||
|
181 | 181 | profiles = list_profiles_in(os.getcwd()) |
|
182 | 182 | if profiles: |
|
183 | 183 | print() |
|
184 | print("Available profiles in current directory (%s):" % os.getcwd()) | |
|
185 | self._print_profiles(profiles) | |
|
186 | ||
|
184 | print( | |
|
185 | "Profiles from CWD have been removed for security reason, see CVE-2022-21699:" | |
|
186 | ) | |
|
187 | ||
|
187 | 188 | print() |
|
188 | 189 | print("To use any of the above profiles, start IPython with:") |
|
189 | 190 | print(" ipython --profile=<name>") |
@@ -188,7 +188,7 b' class ProfileDir(LoggingConfigurable):' | |||
|
188 | 188 | is not found, a :class:`ProfileDirError` exception will be raised. |
|
189 | 189 | |
|
190 | 190 | The search path algorithm is: |
|
191 | 1. ``os.getcwd()`` | |
|
191 | 1. ``os.getcwd()`` # removed for security reason. | |
|
192 | 192 | 2. ``ipython_dir`` |
|
193 | 193 | |
|
194 | 194 | Parameters |
@@ -200,7 +200,7 b' class ProfileDir(LoggingConfigurable):' | |||
|
200 | 200 | will be "profile_<profile>". |
|
201 | 201 | """ |
|
202 | 202 | dirname = u'profile_' + name |
|
203 |
paths = [ |
|
|
203 | paths = [ipython_dir] | |
|
204 | 204 | for p in paths: |
|
205 | 205 | profile_dir = os.path.join(p, dirname) |
|
206 | 206 | if os.path.isdir(profile_dir): |
@@ -2,6 +2,50 b'' | |||
|
2 | 2 | 8.x Series |
|
3 | 3 | ============ |
|
4 | 4 | |
|
5 | ||
|
6 | IPython 8.0.1 (CVE-2022-21699) | |
|
7 | ------------------------------ | |
|
8 | ||
|
9 | IPython 8.0.1, 7.31.1 and 5.11 are security releases that change some default | |
|
10 | values in order to prevent potential Execution with Unnecessary Privileges. | |
|
11 | ||
|
12 | Almost all version of IPython looks for configuration and profiles in current | |
|
13 | working directory. Since IPython was developed before pip and environments | |
|
14 | existed it was used a convenient way to load code/packages in a project | |
|
15 | dependant way. | |
|
16 | ||
|
17 | In 2022, it is not necessary anymore, and can lead to confusing behavior where | |
|
18 | for example cloning a repository and starting IPython or loading a notebook from | |
|
19 | any Jupyter-Compatible interface that has ipython set as a kernel can lead to | |
|
20 | code execution. | |
|
21 | ||
|
22 | ||
|
23 | I did not find any standard way for packaged to advertise CVEs they fix, I'm | |
|
24 | thus trying to add a ``__patched_cves__`` attribute to the IPython module that | |
|
25 | list the CVEs that should have been fixed. This attribute is informational only | |
|
26 | as if a executable has a flaw, this value can always be changed by an attacker. | |
|
27 | ||
|
28 | .. code:: | |
|
29 | ||
|
30 | In [1]: import IPython | |
|
31 | ||
|
32 | In [2]: IPython.__patched_cves__ | |
|
33 | Out[2]: {'CVE-2022-21699'} | |
|
34 | ||
|
35 | In [3]: 'CVE-2022-21699' in IPython.__patched_cves__ | |
|
36 | Out[3]: True | |
|
37 | ||
|
38 | Thus starting with this version: | |
|
39 | ||
|
40 | - The current working directory is not searched anymore for profiles or | |
|
41 | configurations files. | |
|
42 | - Added a ``__patched_cves__`` attribute (set of strings) to IPython module that contain | |
|
43 | the list of fixed CVE. This is informational only. | |
|
44 | ||
|
45 | Further details can be read on the `GitHub Advisory <https://github.com/ipython/ipython/security/advisories/GHSA-pq7m-3gw7-gq5x>`__ | |
|
46 | ||
|
47 | ||
|
48 | ||
|
5 | 49 | IPython 8.0 |
|
6 | 50 | ----------- |
|
7 | 51 |
General Comments 0
You need to be logged in to leave comments.
Login now