OS Command Injection In jupyterlab-git
Description
jupyterlab-git has a command injection vulnerability in "Open Git Repository in Terminal"
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.
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
Create a new directory via mkdir test/ && cd test/.
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 ..
Start JupyterLab from test/ by running jupyter lab.
With JupyterLab open in the browser, double click on $(touch pwned.txt) in the file browser.
From the top menu bar, click "Git > Open Git Repository in Terminal".
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.
Patch (click to expand)
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 => {...
This patch removes the cd <git-repo-path> shell command that causes the issue. To preserve the existing behavior, the cwd argument is set to <git-repo-path> when a terminal session is created via the terminal:create-new JupyterLab command. This preserves the existing application behavior while mitigating the command injection issue.
We have verified that this patch works when applied to a local installation of jupyterlab-git. We have also verified that the cwd argument is available in all versions of JupyterLab 4, so this patch should be fully backwards-compatible.
Workarounds
We recommend that users upgrade to the patched versions listed on this GHSA. However, if a user is unable to upgrade, there are 3 different ways to mitigate this vulnerability without upgrading to a patch.
Disable terminals on jupyter-server level:
c.ServerApp.terminals_enabled = False
Disable the terminals server extension:
jupyter server extension disable jupyter_server_terminals
Disable the lab extension:
jupyter labextension disable @jupyterlab/terminal-extension
Footnotes
Mitigation
Update Impact
Minimal update. May introduce new vulnerabilities or breaking changes.
Ecosystem | Package | Affected version | Patched versions |
|---|---|---|---|
pypi | 0.51.1 |
Aliases
References