CVE-2022-39286: Uncontrolled Search Path Element (CWE-427)
value: Jupyter Core is a package for the core common functionality of Jupyter projects. Jupyter Core prior to version 4.11.2 contains an arbitrary code execution vulnerability in `jupyter_core` that stems from `jupyter_core` executing untrusted files in CWD. This vulnerability allows one user to run code as another. Version 4.11.2 contains a patch for this issue. There are no known workarounds.
CWE description: The product uses a fixed or controlled search path to find resources, but one or more locations in that path can be under the control of unintended actors.
CVSS v3 base score: 8.8
Published: 2022-10-26T20:15Z
Repository: https://github.com/jupyter/jupyter_core
Language: Python
Files changed: jupyter_core/application.py, jupyter_core/tests/test_application.py
Commit date: 2022-10-19 09:09:38 -0500
Commit message: Merge pull request from GHSA-m678-f26j-3hrp

Diff: diff --git a/jupyter_core/application.py b/jupyter_core/application.py
index cb46d12..76204e4 100644
--- a/jupyter_core/application.py
+++ b/jupyter_core/application.py
@@ -86,12 +86,12 @@ class JupyterApp(Application):
 
     @property
     def config_file_paths(self):
         path = jupyter_config_path()
         if self.config_dir not in path:
+            # Insert config dir as first item.
             path.insert(0, self.config_dir)
-        path.insert(0, os.getcwd())
         return path
 
     data_dir = Unicode()
 
     def _data_dir_default(self):
diff --git a/jupyter_core/tests/test_application.py b/jupyter_core/tests/test_application.py
index ed854c8..bdf8d0c 100644
--- a/jupyter_core/tests/test_application.py
+++ b/jupyter_core/tests/test_application.py
@@ -67,47 +67,55 @@ def test_generate_config():
     assert os.path.exists(os.path.join(td, "dummy_app_config.py"))
 
 
 def test_load_config():
     config_dir = mkdtemp()
-    wd = mkdtemp()
+    os.environ["JUPYTER_CONFIG_PATH"] = str(config_dir)
     with open(pjoin(config_dir, "dummy_app_config.py"), "w", encoding="utf-8") as f:
         f.write("c.DummyApp.m = 1\n")
         f.write("c.DummyApp.n = 1")
-    with patch.object(os, "getcwd", lambda: wd):
-        app = DummyApp(config_dir=config_dir)
-        app.initialize([])
+
+    app = DummyApp(config_dir=config_dir)
+    app.initialize([])
 
     assert app.n == 1, "Loaded config from config dir"
+    assert app.m == 1, "Loaded config from config dir"
+
+    shutil.rmtree(config_dir)
+    del os.environ["JUPYTER_CONFIG_PATH"]
 
-    with open(pjoin(wd, "dummy_app_config.py"), "w", encoding="utf-8") as f:
-        f.write("c.DummyApp.n = 2")
 
+def test_load_config_no_cwd():
+    config_dir = mkdtemp()
+    wd = mkdtemp()
+    with open(pjoin(wd, "dummy_app_config.py"), "w", encoding="utf-8") as f:
+        f.write("c.DummyApp.m = 1\n")
+        f.write("c.DummyApp.n = 1")
     with patch.object(os, "getcwd", lambda: wd):
         app = DummyApp(config_dir=config_dir)
         app.initialize([])
 
-    assert app.m == 1, "Loaded config from config dir"
-    assert app.n == 2, "Loaded config from CWD"
+    assert app.n == 0
+    assert app.m == 0
 
     shutil.rmtree(config_dir)
     shutil.rmtree(wd)
 
 
 def test_load_bad_config():
     config_dir = mkdtemp()
-    wd = mkdtemp()
+    os.environ["JUPYTER_CONFIG_PATH"] = str(config_dir)
     with open(pjoin(config_dir, "dummy_app_config.py"), "w", encoding="utf-8") as f:
         f.write('c.DummyApp.m = "a\n')  # Syntax error
-    with patch.object(os, "getcwd", lambda: wd):
-        with pytest.raises(SyntaxError):
-            app = DummyApp(config_dir=config_dir)
-            app.raise_config_file_errors = True
-            app.initialize([])
+
+    with pytest.raises(SyntaxError):
+        app = DummyApp(config_dir=config_dir)
+        app.raise_config_file_errors = True
+        app.initialize([])
 
     shutil.rmtree(config_dir)
-    shutil.rmtree(wd)
+    del os.environ["JUPYTER_CONFIG_PATH"]
 
 
 def test_runtime_dir_changed():
     app = DummyApp()
     td = mkdtemp()

Vulnerable code:         path.insert(0, os.getcwd())
    wd = mkdtemp()
    with patch.object(os, "getcwd", lambda: wd):
        app = DummyApp(config_dir=config_dir)
        app.initialize([])
    with open(pjoin(wd, "dummy_app_config.py"), "w", encoding="utf-8") as f:
        f.write("c.DummyApp.n = 2")
    assert app.m == 1, "Loaded config from config dir"
    assert app.n == 2, "Loaded config from CWD"
    wd = mkdtemp()
    with patch.object(os, "getcwd", lambda: wd):
        with pytest.raises(SyntaxError):
            app = DummyApp(config_dir=config_dir)
            app.raise_config_file_errors = True
            app.initialize([])
    shutil.rmtree(wd)
Fixed code:             # Insert config dir as first item.
    os.environ["JUPYTER_CONFIG_PATH"] = str(config_dir)

    app = DummyApp(config_dir=config_dir)
    app.initialize([])
    assert app.m == 1, "Loaded config from config dir"

    shutil.rmtree(config_dir)
    del os.environ["JUPYTER_CONFIG_PATH"]
def test_load_config_no_cwd():
    config_dir = mkdtemp()
    wd = mkdtemp()
    with open(pjoin(wd, "dummy_app_config.py"), "w", encoding="utf-8") as f:
        f.write("c.DummyApp.m = 1\n")
        f.write("c.DummyApp.n = 1")
    assert app.n == 0
    assert app.m == 0
    os.environ["JUPYTER_CONFIG_PATH"] = str(config_dir)

    with pytest.raises(SyntaxError):
        app = DummyApp(config_dir=config_dir)
        app.raise_config_file_errors = True
        app.initialize([])
    del os.environ["JUPYTER_CONFIG_PATH"]