GitHub Security Advisory: GHSA-cj5w-8mjf-r5f8
Package: jupyterlab-git (PIP)
Severity: HIGH (CVSS 7.4)
CWE: CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Vulnerable versions: < 0.51.1
Patched in: 0.51.1

Summary: jupyterlab-git has a command injection vulnerability in "Open Git Repository in Terminal"

Details:
## Overview

On many platforms, a third party can create a Git repository under a name that includes a shell command substitution [^1] string in the syntax `$(<command>)`. These directory names are allowed in macOS and a majority of Linux distributions [^2]. If a user starts `jupyter-lab` in a parent directory of this inappropriately-named Git repository, opens it, and clicks "Git > Open Git Repository in Terminal" from the menu bar, then the injected command `<command>` is run in the user's shell without the user's permission.

This issue is occurring because when that menu entry is clicked, `jupyterlab-git` opens the terminal and runs `cd <git-repo-path>` through the shell to set the current directory [^3]. Doing so runs any command substitution strings present in the directory name, which leads to the command injection issue described here. A previous patch provided an incomplete fix [^4].

[^1]: https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html
[^2]: https://www.gnu.org/software/libc/manual/html_node/File-Name-Portability.html
[^3]: https://github.com/jupyterlab/jupyterlab-git/blob/7eb3b06f0092223bd5494688ec264527bbeb2195/src/commandsAndMenu.tsx#L175-L184
[^4]: https://github.com/jupyterlab/jupyterlab-git/pull/1196
 

## Scope of Impact

This issue allows for arbitrary code execution via command injection. A wide range of actions are permitted by this issue, including but not limited to: modifying files, exfiltrating data, halting services, or compromising the server's security rules.

We have scanned the source code of `jupyterlab-git` for other command injection risks, and have not found any at the time of writing.

This issue was reproduced on the latest release of `jupyterlab-git`, v0.51.0. The steps taken to reproduce this issue are described in the "Proof-of-concept" section below.
 

## Proof-of-concept

1. Create a new directory via `mkdir test/ && cd test/`.

2. Create a new Git repository under `test/` with a command substitution string in the directory name by running these commands:

```
mkdir '$(touch pwned.txt)'
cd '$(touch pwned.txt)/'
git init
cd ..
```

3. Start JupyterLab from `test/` by running jupyter lab.
4. With JupyterLab open in the browser, double click on `$(touch pwned.txt)` in the file browser.
5. From the top menu bar, click "Git > Open Git Repository in Terminal".
6. Verify that `pwned.txt` is created under `test/`. This demonstrates the command injection issue described here.

## Proof-of-concept mitigation

The issue can be mitigated by the patch shown below.

<details><summary>Patch (click to expand)</summary>

```diff
diff --git a/src/commandsAndMenu.tsx b/src/commandsAndMenu.tsx
index 3779a6c..71ddcea 100644
--- a/src/commandsAndMenu.tsx
+++ b/src/commandsAndMenu.tsx
@@ -164,31 +164,13 @@ export function addCommands(
     label: trans.__('Open Git Repository in Terminal'),
     caption: trans.__('Open a New Terminal to the Git Repository'),
     execute: async args => {
-      cons