Gitは認証の必要なリポジトリへアクセスするとき、ユーザ名とパスワード入力を必要としますが、アクセスするたび入力するのは煩わしいので、資格情報を記憶するために、git-credential-から始まる名前のカスタムヘルパーコマンドが存在します。これらカスタムヘルパーはGitから標準入出力を扱う普通のコマンドで、標準入力経由でGitから渡されたパラメータに従って、対応するパスワードを標準出力を介してGitへ返します。ヘルパーコマンドが呼ばれるルールはgitcredentials(7)に書かれています。
これらのヘルパーコマンドとGitの間で使われるプロトコルがGit credentialプロトコルです。プロトコルは1行に1つのキーバリューが書かれるテキストプロトコルで、リクエストは空行で終わります。ヘルパーコマンドは空行までを読み取って、不足しているパラメータ(通常はパスワードだけ)を返します。これらのパラメータはリポジトリのURLから生成されます。以下はGit credentialプロトコルでパスワードを取得するときの例です。
protocol=https host=github.com username=lufia password=xxx
macOSを使っている場合は、以下のようにするとKeychainからパスワードを取り出せます。最後の空行を忘れないようにしましょう。
% `git --exec-path`/git-credential-osxkeychain get protocol=https host=github.com username=lufia
CVE-2020-5260
日本時間だと4/15 3:00頃にGit 2.26.1がリリースされました。このリリースでCVE-2020-5260というGit credentialプロトコルの脆弱性が修正されました。
上記でみたように、Git credentialプロトコルは改行文字でパラメータを区切ります。ところでURLはパーセントエンコーディングされた値を一部の場所で使うことができるため、https://host?%0a
のように改行文字も与えることができてしまいます。そしてややこしいことに、Gitはcredentialプロトコルで扱うURLのパースを厳密には行っていません。そのため、外部からプロトコルへ介入することができてしまいます。例えば以下の場合、
https://evil.example.com?%0agithub.com/xxx
Git 2.26.0までは、Gitは%0a
をデコードしてヘルパーコマンドへ渡すため、
protocol=https host=evil.example.com host=github.com
のようにhost=パラメータが2回現れます。同じパラメータが届いた場合は後勝ちなのでhost=github.com
のパスワードがGitへ戻されますが、しかしGitが実際に通信するリポジトリのホストはevil.example.comなので、パスワードが漏れてしまって非常にまずいですね、という脆弱性です。
影響
ヘルパーコマンドは、git-remote-httpでリポジトリへアクセスするとき、またはgit imap-send
でパッチを送るときに使われるようでした。そのため、影響を受けるプロトコルは現代ではhttpsがほとんどでしょう。ssh経由でアクセスしている場合はgit-remote-httpを使わないので、おそらく影響しないと思われます(間違っていたら指摘ください)。ただし、SourceTreeなどGitクライアントや、場合によってはHomebrewやGoコンパイラなど、裏でGitコマンドを使っている場合も対象となるので注意が必要です。
やるべきこと
脆弱性が修正されたバージョンにGitをアップデートしましょう。Git credentialのヘルパーコマンドを全て無効化する方法もあるようですが、絶対にアップデートする方が簡単です。
パスワードは変更した方が良いのか
信用できるリポジトリしか扱わない前提があれば、パスワードの変更は不要だとは思いますが、少しでも不安なら変更した方が安全だと思います。