GitHubのWebhook送信元IPに3範囲追加|許可リストの点検手順と、署名で送り主を確かめる方法
GitHubが10月29日、Webhookの送信元IPに3つの範囲を追加したと告知
GitHubは2026年10月29日、github.comのWebhookを送り出すIPアドレスの範囲を3つ追加したと公式の変更履歴(Changelog)で告知しました。追加されたのは 9.234.98.160/28、9.234.98.176/28、9.234.106.48/28 です。GitHub Enterprise Cloudを含む、github.comのすべてのプランのWebhookが対象です。
Webhookはリポジトリへのpushやプルリクエストの作成といった出来事を、GitHubが外部のサーバーへ知らせる仕組みです。自動デプロイ、CI、チャットへの通知などの受け口として使われています。受け口のサーバーを守るために「GitHubのIPアドレスから来た通信だけを受け付ける」設定(IPアドレスの許可リスト)を使っている場合、新しい範囲から届いたWebhookは、リストに足りなければ拒否されます。
この記事では、追加された範囲と、GitHubがIPアドレスの一覧を公開している「Meta API」での扱いを確かめたうえで、自分の許可リストに足りない範囲があるかを調べる手順と、IPアドレスとは別にWebhookの送り主を確かめる署名の確認をまとめます。手順はMacのターミナルで実行して確かめました。
この変更の要点
IPアドレスでWebhookの受信を絞っているなら、3つの範囲を許可リストへ
追加された範囲
IPv4の3範囲、計48アドレス
9.234.98.160/28、9.234.98.176/28、9.234.106.48/28 です。
対応が必要な人
送信元IPを手で書いたリストで絞っている人
Meta APIから一覧を作り直している場合は、10月8日17時(協定世界時)より後に取り直した一覧なら入っています。
確かめ方
GitHubが公開するIPの一覧と比べる
一覧(Meta APIの「hooks」)と許可リストを、curlとPythonで照らし合わせます。
合わせて確認
署名でも送り主を確かめる
X-Hub-Signature-256 の確認は、IPアドレスが変わっても使えます。
追加された3つのIP範囲は、10月上旬からMeta APIの「hooks」に載っていた
GitHubは自社のサービスが使うIPアドレスの一覧を Meta API(https://api.github.com/meta)で公開しています。一覧は用途ごとに分かれていて、Webhookの送信元は「hooks」という項目です。10月31日に取得したhooksには、IPv4が7つ、IPv6が2つ、合わせて9つの範囲が並んでいました。
Webサイトの保存サービスInternet Archive(Wayback Machine)に残るMeta APIの保存版と比べると、3つの範囲が加わった時期も分かります。9月7日から10月6日までの保存版7点では、hooksは6つでした。10月8日以降の保存版3点では、今回の3つを含む9つになっています。Changelogでの告知は10月29日なので、Meta APIから一覧を取り直している人のリストには、告知より3週間ほど前から入っていたことになります。
10月6日までの保存版(6範囲)
以前からある範囲
192.30.252.0/22
185.199.108.0/22
140.82.112.0/20
143.55.64.0/20
2a0a:a440::/29
2606:50c0::/32
10月8日以降の保存版と現在(9範囲)
左の6範囲に、次の3つが加わった
9.234.98.160/28
9.234.98.176/28
9.234.106.48/28
/28は16アドレス分の範囲です。3つで48アドレスになります。
出典: Meta API(2026年10月31日に取得)と、Wayback Machineに残るMeta APIの保存版(9月7日〜10月23日の10点、協定世界時)。10月6日6時42分の版に3範囲はなく、10月8日16時58分の版にはありました。
新しい3つの範囲はhooksのほかに、GitHub Actionsの実行環境の項目「actions」にある 9.234.0.0/17 にも含まれます。actionsの範囲を含め、Meta APIに載る範囲をまとめて許可している環境では、以前から通る状態でした。ただしactionsの範囲はGitHubが用意する実行環境を多くの利用者が共有して使う範囲です。GitHubの説明どおり、ほかの利用者のワークフローからの通信もこの範囲から来るため、Webhookの受け口で許可する範囲にはhooksを使います。
対応が必要なのは、Webhookの送信元IPを固定のリストで絞っているサーバー
影響があるかどうかは、Webhookの受け口でIPアドレスによる制限をかけているかと、その一覧の作り方で決まります。次の順に確かめると、自分の環境で何をすればよいかが分かります。
Webhookの受け口で確かめること
質問1
ファイアウォール、リバースプロキシ、クラウドのアクセス制御などで、Webhookの受信をGitHubのIPアドレスに絞っている?
絞っていない → 今回の追加で設定を変える必要はありません。下の「IPアドレスに加えて、署名でGitHubからの送信だと確かめる」節を確認してください。
絞っている → 質問2へ
質問2
許可リストは、Meta APIから自動で作り直している?
自動で作り直している → 10月8日17時(協定世界時)より後に取り直した一覧なら、3範囲は入っています。次の節の手順で、念のため確かめます。
手で書いて固定している → 3範囲を追加します。
追加したあと
拒否されていたWebhookは、GitHubの「Recent deliveries」で失敗として残ります。過去3日分までは「Redeliver」で送り直せます。
許可リストで拒否されたWebhookは、受け口のアプリまで届きません。デプロイが動かない、通知が来ないといった形で気づくことが多く、GitHub側では「Recent deliveries」に失敗として記録されます。GitHubは失敗したWebhookを自動では送り直しません。GitHubの説明どおり、受け取れなかった分は手で、または送り直しのスクリプトで再送します。
1
リポジトリの「Settings」を開く
2
左の「Webhooks」から対象のURLを選ぶ
3
「Recent deliveries」で失敗した送信を探す
4
送信の識別子(GUID)を開き「Redeliver」を押す
出典: GitHub Docs「Redelivering webhooks」。送り直せるのは過去3日分で、リポジトリの管理者権限が必要です。Organizationに設定したWebhookはOrganizationのオーナーが、GitHub AppのWebhookはAppのオーナーか管理者が、それぞれの設定画面の「Recent deliveries」から送り直します。
Webhookの許可リストに足りない範囲を、Meta APIと比べて確かめる
まず、いまのWebhookの送信元を一覧で表示します。curlとjqを使うコマンドで、手元のMac(macOS 27.0.1)では両方とも最初から入っていました。ターミナルに貼り付けて実行してください。jqがない環境では、次に紹介するPythonのスクリプトだけでも確かめられます。Macで初めて python3 を実行すると、コマンドライン・デベロッパ・ツールのインストールを求められることがあります。
curl -s https://api.github.com/meta | jq -r '.hooks[]'
9.234.106.48/28
9.234.98.160/28
9.234.98.176/28
192.30.252.0/22
185.199.108.0/22
140.82.112.0/20
143.55.64.0/20
2a0a:a440::/29
2606:50c0::/32
許可リストに範囲が少ないうちは、この出力と目で見比べれば足ります。リストに広い範囲(たとえば 9.234.0.0/16)を書いている場合は、文字列が一致しなくても中に含まれていることがあります。そこで、範囲どうしの包含関係まで調べる短いPythonスクリプトを用意しました。許可リストの隣り合う範囲をまとめたうえで、hooksの各範囲がどれか1行の範囲に丸ごと含まれるかを判定します。/28 を2つの /29 に分けて書いたリストも、まとめてから比べるので含まれると判定されます。Pythonの標準ライブラリだけで動きます。
次の内容を check_hooks.py という名前で保存し、許可リストを1行に1範囲ずつ書いた allowlist.txt を同じフォルダに置きます。
import ipaddress
import json
import sys
import urllib.request
META_URL = "https://api.github.com/meta"
def load_hooks(source):
if source.startswith("https://"):
with urllib.request.urlopen(source, timeout=10) as res:
meta = json.load(res)
else:
with open(source, encoding="utf-8") as f:
meta = json.load(f)
return [ipaddress.ip_network(x) for x in meta["hooks"]]
def load_allowlist(path):
nets = []
with open(path, encoding="utf-8") as f:
for line in f:
line = line.split("#", 1)[0].strip()
if line:
nets.append(ipaddress.ip_network(line, strict=False))
return nets
def merge(nets):
v4 = ipaddress.collapse_addresses(n for n in nets if n.version == 4)
v6 = ipaddress.collapse_addresses(n for n in nets if n.version == 6)
return list(v4) + list(v6)
def covered(net, allow):
return any(
net.version == a.version and net.subnet_of(a) for a in allow
)
def main():
if len(sys.argv) < 2:
print("usage: python3 check_hooks.py allowlist.txt [meta.json]")
return 2
allow = merge(load_allowlist(sys.argv[1]))
hooks = load_hooks(sys.argv[2] if len(sys.argv) > 2 else META_URL)
missing = [str(n) for n in hooks if not covered(n, allow)]
print(f"GitHubのWebhook送信元: {len(hooks)}件")
print(f"許可リストに含まれる: {len(hooks) - len(missing)}件")
if missing:
print("足りない範囲:")
for m in missing:
print(f" {m}")
return 1
print("足りない範囲はありません")
return 0
if __name__ == "__main__":
sys.exit(main())
ターミナルでそのフォルダへ移動し、次を実行します。
python3 check_hooks.py allowlist.txt
10月6日までの6範囲だけを書いた許可リストで実行すると、今回の3範囲が「足りない範囲」として表示され、終了コードは1になりました。Meta APIから作り直したリスト、9.234.0.0/16 を含む広いリスト、3範囲をそれぞれ2つの /29 に分けて書いたリストでは、足りない範囲は0件でした。
要追加:10月6日までの6範囲のリスト
GitHubのWebhook送信元: 9件
許可リストに含まれる: 6件
足りない範囲:
9.234.106.48/28
9.234.98.160/28
9.234.98.176/28
対応済み:Meta APIから作ったリスト
GitHubのWebhook送信元: 9件
許可リストに含まれる: 9件
足りない範囲はありません
2026年10月31日、macOS 27.0.1のPython 3.9.6で実行した出力。
足りない範囲が出たら、使っている仕組み(ファイアウォール、nginxなどのリバースプロキシ、クラウドのセキュリティグループなど)の許可リストに追加します。GitHubのWebhookのベストプラクティスは、IPアドレスで絞る場合はMeta APIから最新の一覧を取り、定期的に更新するよう勧めています。上のスクリプトは終了コードで結果を返すので、定期実行やCIに組み込めば、次に範囲が増えたときにも気づけます。
IPアドレスに加えて、署名でGitHubからの送信だと確かめる
GitHubは自社のIPアドレスについて説明するページで、IPアドレスによるアクセス許可を勧めておらず、使う場合はMeta APIを定期的に確認するよう求めています。範囲は今回のように増えるため、固定の許可リストは更新が遅れると、新しい範囲から届くWebhookを拒否します。
そこで合わせて使いたいのが、Webhookの署名です。Webhookに「Secret」(合言葉にあたる文字列)を設定すると、GitHubは送る内容とSecretから計算した値を X-Hub-Signature-256 というヘッダーに付けます。受け口で同じ計算をして一致すれば、Secretを知るGitHubから届いた、途中で書き換えられていない内容だと確かめられます。この確認は送信元のIPアドレスが変わっても同じように使えます。
Pythonでは、GitHubの説明にあるPythonの例をもとにした次の関数で確かめられます。署名は送られてきた本文そのものから計算されるので、受け取った本文はJSONとして読み込む前のバイト列(Pythonの bytes)のまま渡します。比較には、GitHubが勧めるとおり == の代わりに hmac.compare_digest を使い、両方をバイト列にそろえて比べます。署名ヘッダーに日本語などASCII以外の文字が混ざった不正な送信も、エラーで止まらずに拒否できます。
import hashlib
import hmac
def is_valid_github_signature(raw_body, secret, header):
if not header:
return False
digest = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest()
expected = "sha256=" + digest
return hmac.compare_digest(expected.encode("utf-8"), header.encode("utf-8"))
GitHubの説明に載っている例の値(Secretが「It's a Secret to Everybody」、本文が「Hello, World!」)で試すと、記載どおりの署名と一致しました。本文を1文字変えたもの、署名ヘッダーがないもの、署名ヘッダーに日本語が入ったものは拒否されます。
受け付ける
GitHubの例と同じ本文と署名
拒否する
本文を1文字変えた(「!」を「?」に)
拒否する
署名ヘッダーが付いていない
拒否する
署名ヘッダーに日本語が入っている
2026年10月31日、macOS 27.0.1のPython 3.9.6で上の関数を実行した結果。期待する署名は sha256=757107ea…3e17(GitHub Docsの例)。
Secretは推測されにくい長い文字列にし、受け口のサーバーだけが読める場所に置きます。まだSecretを設定していないWebhookは、リポジトリの「Settings」→「Webhooks」で対象のURLを開き、「Secret」欄に入れて保存すると、以後の送信に署名が付きます。
署名を確かめるようにしても、IPアドレスの許可リストで拒否された通信は受け口に届きません。IPアドレスで絞り続ける場合は、許可リストをMeta APIから定期的に作り直し、署名は送り主の確認として併せて使います。
Webhookの許可リストを点検し、署名の確認も入れておく
GitHubがWebhookの送信元に加えた3つの範囲は、Meta APIの「hooks」には10月上旬から載っていました。送信元IPで受信を絞っているサーバーは、curl -s https://api.github.com/meta | jq -r '.hooks[]' の出力か上のスクリプトで許可リストを点検し、足りない範囲を追加してください。拒否されたWebhookは、過去3日分なら「Recent deliveries」から送り直せます。IPアドレスで絞り続けるなら、許可リストはMeta APIから定期的に作り直します。あわせて X-Hub-Signature-256 の署名を確かめるようにしておくと、IPアドレスとは別の方法で、GitHubから届いた書き換えられていない内容かを確かめられます。












