2020/04/05 12:30 その後の顛末を追記しました。
この記事の続きです。
GitHub上でマージした変更内容をSlackに通知するGitHub Actionsを実装して意気揚々としていたところ、次のようなツッコミをもらったところまで書きました。
そういえばこれって Pull Request Title Injection できないですかね? まあ、タイトル書くの社員なのでいいんですが。
Pull Request Title Injectionについて
Pull Request Title Injection とは
そもそもPull Request Title Injectionとはどういうことでしょう?何を指すのか? 簡単に言うと、Pull Requestのタイトルに不正な文字列を設定することで、このGitHub Actionsを通じて任意のメッセージをSlackに通知できる(更に、任意のコマンドを実行できてしまうかもしれない)攻撃方法です。 例えば、前回の記事で紹介したActionsが設定されたリポジトリに対して、次のようなタイトルのPull Requestを作成します。
Test Pull Request Title Injection", footer: ":male-police-officer: Injection!! :male-police-officer:
このPull Requestを閉じた時、Slackには以下のようなメッセージが投稿されます。
おわかりでしょうか?Actionsでは pretext
、title
、title_link
しか設定していないにも関わらず、メッセージのfooter
に文字列が挿入されています。一体どういうことでしょうか?
Injection はなぜ発生したのか?
ここでもう一度Actionsの設定を見てみましょう。スコープをわかりやすくするため、jq
コマンドに渡しているJSONの部分のみ切り出します。
{ attachments: [{ pretext: "Swagger が更新されたよ!", color: "good", title: "${{ github.event.pull_request.title }}", title_link: "${{ github.event.pull_request.html_url }}" }] }
title
に設定している ${{ github.event.pull_request.title }}
はPull Requestのタイトルに一致するため、ここに上述のような文字列を設定した場合、任意のコマンドを実行できてしまう(かもしれない)わけですね。SQL Injectionと全く同じ手口です。怖い怖い。
Injectionの対策
Pull Request Title Injectionの概要がわかったところで、次はその対策です。
toJSON関数を使う
GitHub ActionsにはActions内部で使える特別な関数がいくつかあり、今回はその中のtoJSON関数を使います。
Context and expression syntax for GitHub Actions - GitHub Help
toJSON関数は引数に渡したコンテキストをJSON形式で出力してくれる関数です。コンテキストのデータに特殊文字が含まれている場合、toJSON関数がいい感じにエスケープしてくれる(っぽい)です。問題となっているPull Requestのタイトルの部分にこの関数を噛ませてあげることで、今回のようなInjectionを回避できます。
name: notify on: pull_request: types: ['closed'] paths: - 'webapi/swagger/**' branches: - master jobs: notify: name: Slack Notification runs-on: ubuntu-latest steps: - name: 'Send Notification' run: | jq -n '{ attachments: [{ pretext: "Swagger が更新されたよ!", color: "good", title: ${{ toJSON(github.event.pull_request.title) }}, title_link: "${{ github.event.pull_request.html_url }}" }] }' | curl -H 'Content-Type: application/json' -d @- ${{ secrets.SLACK_WEBHOOK }}
実際に動かしてみると、以下のようなメッセージが投稿されます。title
の部分にPull Requestのタイトルが全て挿入されているのがわかります。
実行ログはこちらから確認できます。 JSONの特殊文字がちゃんとエスケープされて渡されていることがわかると思います。
まとめ
GitHub Actionsで発生し得るPull Request Title Injectionの概要とその対策としてtoJSON関数を使う方法を紹介しました。 詳しく調べてませんが、以前の記事で紹介したいくつかのSlack通知Actionsでも同様のInjectionが実行できるようです。 Slack通知に限らず、Pull RequestのコンテキストをActionsのパラメータとして利用したい場合は十分気をつけましょう。
また、他にもInjection対策の方法があれば是非教えてください。
2020/04/05追記: 出題者よりお便り
こちらの記事を公開したところ、最初に議題を提案してくれた @shogo82148 よりまだまだ甘いぞというお手紙をいただきました。
RE: Pull Request Title Injection とその対策
。。精進しよう。。