virtualenv bash activate は、環境名にバックスラッシュが先行するコマンドを実行します。
### 概要
bash の `activate` スクリプトは、`PS1` に対して bash が行う 2 回の処理のうち、片方の処理でのみ環境名をエスケープします。そのため、環境名にバックスラッシュが含まれている場合、エスケープが解除され、`\$(...)` を含む環境名が、ユーザーのシェルでコマンドとして実行されます。これは、bash がプロンプトを表示するたびに発生します。
### 影響範囲
`src/virtualenv/activation/bash/activate.sh` の、環境名を `PS1` の先頭に追加する部分。
### 攻撃者による制御入力
環境名:環境ディレクトリの名前、または `--prompt` オプションまたは `VIRTUALENV_PROMPT` の値。攻撃者は、例えば、ブランチ、プロジェクト、またはジョブの名前を渡す CI ジョブやラッパーツール、またはクローンされたリポジトリまたは展開されたアーカイブ内のディレクトリなどを通じて、この値を操作する必要があります。`--prompt .` は、現在のディレクトリの名前を使用します。
### 詳細
bash は、プロンプトを表示するたびに、`PS1` に対して 2 回の処理を行います。まず、バックスラッシュによるエスケープを解釈し、`\\` を `\` に、`\$` を `$` に変換します(root ユーザーの場合は `#`)。次に、結果に対してパラメータ展開、コマンド置換、および算術展開を実行します。バージョン 21.13.0 以降では、スクリプトは環境名内のバックスラッシュ、ドル記号、およびバッククォートをエスケープしますが、これは 2 回目の処理でのみ行われます。そのため、エスケープ処理の最初の段階で、環境名に先行するバックスラッシュによってエスケープが解除されます。バージョン 21.13.0 より前のバージョンでは、環境名は一切エスケープされません。root ユーザーとして実行されている bash は、`\$` を `#` に変換するため、ペイロードは誤ったテキストを表示しますが、何も実行しません。zsh はエスケープ処理を行わないため、影響を受けません。
### 実証コード
```console
$ virtualenv --prompt 'a\$(touch PWNED)' env
$ bash --norc --noprofile -c 'source env/bin/activate; printf "%s" "${PS1@P}"'
$ ls PWNED
PWNED
```
### 影響
攻撃者が環境名を操作し、その環境の `activate` スクリプトをソースするユーザーのシェルで、そのユーザーの権限で、プロンプトが表示されるたびに任意のコマンドが実行される可能性があります。
### テスト対象バージョン
21.14.6を、Debian bookworm上でbash 5.2.15を使用し、一般ユーザーとrootユーザーの両方でテストしました。
### 既知の対策
`activate`スクリプトを実行する前に、`VIRTUAL_ENV_DISABLE_PROMPT=1`を設定すると、`PS1`変数が変更されずに済みます。または、プロンプトの展開が不要な場合は、`shopt -u promptvars`を実行してください。`activate`スクリプトを実行する前に、作成していない環境の名前を確認してください。
### 最新リリース
- [x] 最新のvirtualenvリリースでも問題が再現されます。
21.14.6
### 修正
21.14.7で修正されました。bash環境では、`activate`スクリプトが、バックスラッシュ、ドル記号、およびバッククォートを両方の処理でエスケープするように変更されました。これにより、上記の例では何も実行されず、プロンプトには指定された名前が表示されます。zshは、必要なエスケープ処理を維持しています。
修正: https://github.com/pypa/virtualenv/commit/c3104e02474b652832a9bbaae79f6e1696296932
### 貢献者
Anthropic OSS Scannerのビルドイメージ内で、rootユーザーとしてvirtualenvのテストスイートを実行中に発見されました。
影響を受けるパッケージ:
- pip (Python) virtualenv: 影響を受けるバージョンは21.14.6以下、21.14.7で修正済み。