新版 iphone 【MFi認証】ライトニングケーブル 2M 3本セット 充電器 ケーブル 最大2.4A急速充電 lightning 断線防止 超高耐久 iPhone14/14 Pro/14 ProMax/13/13 Pro/12/12 ProMax/11/X/8/iPad/AirPods/MacBookなど各種対応
¥799 (2025年4月26日 13:09 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)
先日起きた tj-actions や reviewdog のセキュリティインシデントのレポートを読みました。
その内容を個人的な検証結果や感想を挟みつつかいつまんで書きたいと思います。
詳細は原文を読んでください。
なお、侵害された repository 及び tag は全て修正され、盗まれた Personal Access Token (PAT) も revoke されているはずです。
攻撃の流れ
tj-actions/changed-files が侵害されるまでに複数の PAT の流出及びリポジトリの侵害が連鎖的に起こっています。
つまり tj-actions/changed-files が直接的にいきなり侵害されたというより、複数のリポジトリをいわば踏み台のようにして侵害したという感じでしょうか。
攻撃者は PAT が盗まれたりした GitHub Account とは別に複数の GitHub Account を使って攻撃を行っています。
ちなみに今回見つかった悪意のあるユーザーは全て削除されているようです(それはそう)。
まぁインシデントと同時期にアカウントが削除されているので調査で怪しいアカウントとして目をつけられたというのもあるでしょう。
- spotbugs/sonar-findbugs の pull_request_target workflow が悪用され、 secrets に登録していた PAT が流出
- PAT を悪用して spotbugs/spotbugs に悪意のあるユーザー jurkaofavak を招待
- jurkaofavak が spotbugs/spotbugs にブランチ
hewrkbwkyk
を一瞬作成し、即削除。その push event で悪意のある workflow が実行され、 secrets に登録していた spotbugs/spotbugs のメンテナの PAT が流出。流出した PAT は reviewdog/action-setup の write 権限を持っていた -
reviewdog/action-setup
の Fork を作成し、 Fork に悪意のある commit を作成 -
reviewdog/action-setup
のv1
tag を書き換え、 Fork repo の悪意のある commit に向ける -
tj-actions/eslint-changed-files が内部的に侵害された
reviewdog/action-setup@v1
を実行しており、 tj-actions/changed-files のリポジトリでtj-actions/eslint-changed-files
が使われていたため、侵害されたコードが tj-actions/changed-files で実行され、 Machine Usertj-bot-actions
の PAT が盗まれる -
tj-actions/changed-files
の Fork を作成し、悪意のある commit を作成 -
tj-bot-actions
の PAT を使ってtj-actions/changed-files
の全タグが Fork の悪意のある commit に書き換えられる
攻撃者は tj-actions/changed-files に依存する coinbase/agentkit を標的にしたと思われますが、幸いにも agentkit から secret が流出したりすることはなかったようです。
Our team also discovered that the initial attack targeted Coinbase.
The payload was focused on exploiting the public CI/CD flow of one of their open source projects (agentkit) probably with the purpose of leveraging it for further compromises.
However, the attacker was not able to use Coinbase secrets or publish packages.
pull_request_target の悪用
Surprise! Pull_request_target
pull_request_target は GitHub Actions の Workflow をトリガする event の一つですが、 public repository で使うにはセキュリティ的に非常に注意が必要です。
通常、 pull_request event では Fork からの pull request の場合 workflow 実行時に secret が渡りませんし、 GitHub Actions token も read only になります。
しかし、 pull_request_target では secret が渡りますし GitHub Actions token にも write 権限を付与できます。
workflow 自体は default branch を参照するので改竄できませんが、 workflow で実行しているリポジトリ内のスクリプトは pull request で改竄できるので、悪意のあるコードが実行できてしまいます。
そのため、 public repository では基本 pull_request_target は使わない、 使う場合は workflow 以外のリポジトリのコードを参照しないものに限定するべきでしょう。
なお、自分は以前 pull_request_target を活用してセキュリティを改善する記事を書いていますが、これはあくまで private repository を前提としているため、今回のような問題はないと思います。
reviewdog の auto invite の悪用
Adnan also pointed out that reviewdog uses an auto-invite mechanism.
reviewdog organization では contributor を自動で organization に invite し write 権限を付与する仕組みがありました。
インシデント後は止められています。
Disabled automated inviter workflow.
なお、自動 invite では reviewdog 本体への write 権限は付与されず、 reviewdog 本体が直接的に攻撃されることはなかったようです。
reviewdog は非常に人気のある OSS ですし、非常に多くの Action があります (執筆時点で 52 個の public リポジトリ)。
これらのリポジトリをメンテするのは大変ですし、メンテを継続するために積極的に write 権限を渡したくなるのも理解できます。
ただ、今回はそこを悪用されてしまった形であり、今回のインシデントによってコントリビューターに write 権限を付与するハードルが更に上がってしまったかと思います。
ユーザーからしたらインシデントが収束し自動 invite が止められたらめでたしめでたしという感じですが、メンテナからしたら今後のメンテをどうしていくのかという問題は残っており、これは難しい問題です (reviewdog どうこうというより、一般論として) 。
OSS Project を如何に持続的にメンテしていくかは常に難しい問題ですね。
Fork network の悪用
After a user forks a repository in GitHub, they can add their commits to the fork.
These commits are added to the “fork network” and can be referenced from the original repository.
元のリポジトリとその Fork は Fork network と呼ばれ、それらのリポジトリのcommitは Fork network の他のリポジトリからも参照できます。
今回の検証のためにリポジトリを 2 つ作りました。
- https://github.com/szksh-lab/test-action : Original
- https://github.com/szksh-lab-2/test-action : Fork
commit a0728ffde5a5f398ff82357930f5ad5145bdba6f は Fork repo の commit ですが、 original repo からも参照できます。
多分この黄色い警告を皆さんも見たことがあるかと思います。
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Original の action のバージョンとして Fork の commit を指定できます。
- uses: szksh-lab/test-action@a0728ffde5a5f398ff82357930f5ad5145bdba6f
しかも、 original repo に fork repo の commit を指定して tag も作れます。
もっとも、 tag を作れるなら original repo に commit を push することもできるので態々 fork の commit に向ける必要もないようにも思えますが、 original に commit を push する必要がなくなるのでより痕跡を残さずに済みます。
tag の書き換えは free plan では audit log に残らないらしく、そのため fork の commit に向けるようにすれば audit log に何も残さずに改竄ができます。
Fork repo を消しても Fork network に Fork repo の commit は残るので SHA を指定すれば参照できますし、どの repo の commit なのか trace するのが難しくなります。
なので、例えば Fork から action を update する PR が来てしかも version が full length commit hash で固定されているような場合、本当にその SHA がその action の安全な SHA なのか確認する必要があります。
一見 v4.2.2 のように見えて実は危険な SHA
uses: actions/checkout@>
これを手作業で確認するのは大変ですが、 pinact には –verify option があります。 (突然の宣伝)
--verify
option をつけるとコメントに書かれた version と SHA が一致しない場合エラーになります。
無効な Email を設定して User を隠蔽
Hiding GitHub Users
攻撃者は valid なメールアドレスでアカウントを作成し、悪意のあるcommitを生成した後、 GitHub の Policy で禁止された匿名の email に変更することでその後の行動を trace できなくした可能性があるようです。
匿名の email が使われると GitHub はそのユーザーを public からは見えなくするそうです。
攻撃者はこれを悪用し、 trace を困難にしたと推測しています。
ただ、引用された Policy を見ても public から見えなくするとは書いてないですし、実際にどういう挙動になるのかは自分には良くわかりません。
commit impersonation
We assume that although the attacker had a GitHub token with write permission to the repository, they preferred to disguise their malicious commit by impersonating a valid user in a valid pull request — a technique called “commit impersonation.”
攻撃者は commit impersonation というテクニックを使って valid な他のユーザーになりすましてcommitを生成したようです。
まぁ今回の攻撃を見る限りなりすまさなくても攻撃は成立している気がしますが、後から気づかれにくくする意図があったのでしょうか?
追記: 良く考えたら後から調べたときにユーザーと紐づかない commit や deleted account と紐づく commit は怪しいし、 Renovate になりすますのは妥当な気もしてきました。まぁ Renovate でも不自然ですけど
なりすましはかなり簡単で commit 時に email を @users.noreply.github.com
としてしまえばその commit は指定したユーザーに紐づいてしまいます。
git config user.email ユーザー名>@users.noreply.github.com
今回の攻撃では攻撃者は Renovate になりすましたようですが、 Renovate のような App でも renovate[bot]@users.noreply.github.com
とすればなりすませてしまいます。
この対策としては Branch Ruleset で commit への署名を必須にするのが有効です。
自分の場合、ほぼ全てのリポジトリの全ての branch で commit への署名を必須にしました。
GitHub API を使えば一括で Branch Ruleset を設定できます。
また、 Pull Request の CI で sign されているか check し、されていない場合は PR にコメントすることでコントリビューターに署名を強制しています。
自分で「署名してください」っていうのはストレスなので CI で自動化しています。
ちなみにこの workflow では例外的に pull_request_target
を使っていますが、リポジトリ中のコードは参照していませんしリスクは低いと思っています。
攻撃者は攻撃の機会を伺っていた?
For instance, there is a three-month gap between when the attackers leaked SPTBGS_MNTNR’s PAT and when they abused it.
one possible hypothesis is that the attackers monitored the projects dependent on the tj-actions/changed-files and waited for an opportunity to compromise a high-value target.
攻撃者が spotbugs のメンテナの PAT を奪取してからそれを悪用するまで 3 ヶ月空いています。
これは仮説ですが、攻撃者は tj-actions/changed-files に依存するリポジトリのリストをウォッチし、攻撃する価値の高いリポジトリが tj-actions/changed-files を使うまで機会を伺っていたのかもしれません。
参考