GitHub webhooks allow applications to receive notifications when events occur in a repository. For example, a webhook can notify a deployment service when code is pushed, trigger an automated test when a pull request is opened, or update an internal system when an issue changes.
Many organizations protect webhook endpoints with firewalls, reverse proxies, or network access control rules. These controls can restrict incoming connections to approved IP addresses. However, problems arise when GitHub changes the IP addresses used for webhook delivery and the firewall continues to allow only an outdated list.
The result can be missed notifications, failed automation, and delays in development workflows.
The solution is not to disable network restrictions or manually update firewall rules whenever a delivery fails. Instead, developers should establish a reliable process for retrieving GitHub's published IP ranges, updating the appropriate allowlists, and verifying that webhook delivery continues to work.
This article explains how GitHub webhook IP addresses work, how to maintain firewall rules, and how to troubleshoot delivery failures without weakening security.
Why GitHub Webhook IP Addresses Matter
When an event occurs in a GitHub repository, GitHub sends an HTTP request to the configured webhook URL. The receiving application processes that request and performs the required action.
A simplified flow looks like this:
GitHub Repository Event
|
v
GitHub Webhook Delivery
|
v
Firewall or Reverse Proxy
|
v
Webhook Endpoint
|
v
Application Processes EventIf the firewall rejects the incoming connection, the application may never receive the request.
For example, suppose a company allows traffic from a documented set of GitHub IP addresses. If GitHub begins delivering webhook requests from an address that is not included in the allowlist, the firewall may block those requests.
The application can be healthy, and the webhook configuration can be correct, yet delivery still fails.
Maintaining an accurate allowlist helps prevent this problem while preserving network restrictions.
Understanding GitHub's Published IP Ranges
GitHub publishes network information through its metadata API. Developers can use this information to identify the IP ranges associated with supported GitHub services.
The metadata response includes categories such as hooks, web, and api, along with other service-related information.
For webhook firewall rules, the hooks category is the relevant starting point.
The following example illustrates the structure of a response:
{
"hooks": [
"192.0.2.0/24",
"198.51.100.0/24"
]
}The addresses in this example are reserved for documentation. They are not actual GitHub webhook ranges.
The metadata API returns CIDR notation, which represents an IP address range rather than a single address. For example, an IPv4 CIDR range such as 192.0.2.0/24 represents a network containing multiple addresses.
A firewall or cloud network rule may support CIDR ranges directly. If it does, storing the documented ranges can be simpler than generating a separate rule for every address.
However, the supported range format and maximum number of rules depend on the firewall or network platform.
Step 1: Retrieve the Current Webhook IP Ranges
Use GitHub's metadata API to retrieve the current published information.
A simple command-line request can be made with curl:
curl --fail --silent --show-error \
https://api.github.com/metaThe response contains multiple categories. Avoid copying the entire response into a firewall configuration because not every category represents webhook delivery traffic.
You can extract the hooks field using jq:
curl --fail --silent --show-error \
https://api.github.com/meta |
jq -r '.hooks[]'This command prints the published webhook-related ranges, one per line.
For an automated process, also check the HTTP status code and confirm that the expected JSON structure exists. A failed request, rate limit response, or unexpected payload should not cause the existing firewall rules to be replaced with an empty list.
Do not treat an unsuccessful API request as evidence that GitHub has removed its webhook IP ranges.
Step 2: Compare the Published Ranges With Existing Rules
Before changing firewall rules, compare the latest published ranges with the current allowlist.
A useful update process should identify three groups:
Change | Meaning | Recommended action |
|---|---|---|
New range | A published range is missing from the current rules | Add the range after validation |
Removed range | A previously configured range is no longer published | Remove it according to the approved update policy |
Unchanged range | The range exists in both lists | Keep the existing rule |
Do not remove existing rules until the new metadata has been retrieved and validated successfully.
This distinction is important because firewall updates are security-sensitive. A parsing error or temporary network failure should not leave the webhook endpoint without its intended protection.
In a production environment, save the previous allowlist before applying an update. This provides a reference for reviewing changes and recovering from an incorrect configuration.
Step 3: Automate the Update Process
Manually checking GitHub's metadata is reasonable for a small test environment. It becomes less reliable when multiple firewalls, cloud environments, and deployment pipelines depend on the same information.
A small automation script can retrieve the metadata and produce a validated list of ranges.
The following Python example fetches the metadata and checks that the hooks field contains valid IP networks.
import ipaddress
import json
import urllib.error
import urllib.request
METADATA_URL = "https://api.github.com/meta"
def fetch_hook_ranges():
request = urllib.request.Request(
METADATA_URL,
headers={"Accept": "application/vnd.github+json"},
)
try:
with urllib.request.urlopen(request, timeout=15) as response:
if response.status != 200:
raise RuntimeError(
f"Unexpected HTTP status: {response.status}"
)
payload = json.load(response)
except (urllib.error.URLError, TimeoutError) as exc:
raise RuntimeError(
"Unable to retrieve GitHub metadata"
) from exc
ranges = payload.get("hooks")
if not isinstance(ranges, list) or not ranges:
raise RuntimeError(
"Missing or empty hooks range list"
)
validated_ranges = []
for value in ranges:
if not isinstance(value, str):
raise RuntimeError("Invalid IP range entry")
network = ipaddress.ip_network(value, strict=False)
validated_ranges.append(str(network))
return sorted(set(validated_ranges))
if __name__ == "__main__":
for network in fetch_hook_ranges():
print(network)The script uses Python's standard library, so it does not require an additional package.
The ipaddress.ip_network() function validates each range. The code also rejects a missing or empty hooks list rather than silently accepting it.
This is a retrieval and validation example, not a complete firewall deployment tool. It does not modify network rules, compare the results with an existing allowlist, or confirm that GitHub's published list is suitable for a particular firewall.
For production use, add logging, monitoring, change review, and integration with the firewall platform's supported API.
Step 4: Apply Firewall Changes Safely
After validating the latest ranges, update the firewall or network access control system.
The exact implementation depends on where the webhook endpoint is hosted.
For example, the receiving service might sit behind:
A cloud security group or network firewall.
A web application firewall.
A reverse proxy.
An on-premises firewall.
A managed API gateway.
These components do not necessarily use the same network rules. A cloud security group may control network connectivity, while an application firewall may apply additional request-level policies.
Update the control that actually rejects the connection.
When the platform supports it, prepare the new configuration and validate it before applying the change. Avoid deleting the current allowlist first and adding the replacement later, because the endpoint could temporarily become unreachable or exposed to unintended traffic.
If a firewall has a limit on the number of CIDR rules, verify that the proposed configuration fits within that limit. If it does not, use an appropriate supported network-management approach rather than silently dropping ranges.
Step 5: Verify Webhook Delivery
A successful firewall update should be followed by a delivery test.
Create a test event in a non-production repository or use a suitable test webhook endpoint. Then inspect the webhook delivery information in GitHub.
Check the following:
The request reaches the expected endpoint.
The receiving server records the incoming request.
The endpoint returns an appropriate HTTP status.
The application processes the event successfully.
No firewall or reverse-proxy rule blocks the request.
GitHub webhook deliveries can be retried or redelivered through supported mechanisms, but the receiving application should not depend on retries as its normal delivery strategy.
For production systems, monitor delivery failures and maintain enough logging to distinguish network rejection, authentication failure, invalid payloads, and application errors.
Webhook IP Allowlists Are Not a Replacement for Signature Verification
Allowlisting network ranges helps restrict which source addresses can connect to an endpoint. It does not independently prove that a request is authentic or that its contents have not been modified.
GitHub supports webhook secret-based signature verification. When a webhook secret is configured, the receiving application should verify the request's HMAC signature using the raw request body and the configured secret.
For example, in Python:
import hashlib
import hmac
def verify_github_signature(
secret: bytes,
payload: bytes,
signature_header: str | None,
) -> bool:
if not signature_header:
return False
expected = "sha256=" + hmac.new(
secret,
payload,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(
expected,
signature_header,
)The application should pass the value of GitHub's X-Hub-Signature-256 header as signature_header.
The secret must remain confidential, and the payload must be the original request body used to calculate the signature. Parsing and reserializing JSON before verification can change the bytes and cause verification to fail.
A valid signature confirms that the payload matches the configured secret. It does not prevent replay by itself, so applications should also consider delivery identifiers, idempotent processing, and appropriate handling of repeated requests.
Common Mistakes When Managing GitHub IP Ranges
Allowing every IP address
Opening the endpoint to all source addresses may avoid allowlist maintenance, but it removes an important network restriction. Use a broader policy only when the architecture and security requirements justify it.
Using unrelated GitHub IP categories
The metadata API publishes ranges for different purposes. Do not assume that the web or api ranges are interchangeable with hooks.
Trusting an empty API response
A failed request or parsing problem must not remove existing firewall protection. Validate the response before applying changes.
Updating only one environment
Development, staging, and production may use separate network rules. Track which environments depend on the allowlist and update them consistently.
Verifying only network connectivity
A request may reach the server but still fail because of signature validation, routing, or application errors. Verify the complete delivery process.
Troubleshooting Common Problems
Problem | Possible cause | What to investigate |
|---|---|---|
Webhooks stop arriving after an IP change | New ranges are missing from the allowlist | Compare the current rules with the published |
Metadata retrieval fails | Network, DNS, TLS, or API request failure | Inspect the HTTP response and network connectivity |
The update script returns no ranges | Unexpected response structure or parsing error | Validate the HTTP status and JSON payload |
Requests reach the server but return errors | Application or signature verification failure | Review request headers, raw payload handling, and application logs |
Only some environments receive events | Firewall configurations differ | Compare allowlists across environments |
Firewall updates fail | Rule limits or invalid CIDR entries | Validate ranges and inspect platform-specific limits |
Use firewall logs and GitHub delivery records together. GitHub can show that a delivery failed, while the network logs may reveal whether the request was rejected before reaching the application.
Best Practices for Keeping Firewall Rules Current
A reliable process should make updates repeatable without making them uncontrolled.
Retrieve webhook ranges from GitHub's published metadata API.
Validate the HTTP response and the structure of the returned data.
Compare new ranges with the existing allowlist before making changes.
Preserve the previous configuration for review and rollback.
Automate updates through a controlled script or infrastructure-management workflow.
Apply the minimum network access required by the application's design.
Verify webhook signatures in the receiving application.
Monitor delivery failures and firewall rejections.
Test changes in a non-production environment when practical.
Keep allowlists consistent across every environment that receives webhooks.
Also establish an operational owner for the update process. Automation without monitoring can fail silently, leaving the firewall configuration outdated even though the update job continues to exist.
Summary
GitHub webhook IP changes can interrupt automation when firewall rules no longer include the published source ranges. The solution is to retrieve the current hooks ranges, validate the response, compare it with existing rules, and apply updates through a controlled process.
After every significant change, verify actual webhook delivery rather than relying only on the firewall configuration. Combine network restrictions with webhook signature verification, useful logging, and monitoring.
This approach keeps webhook endpoints protected while reducing the risk that an IP range change disrupts development workflows.

Join the conversation! Your thoughts help the community grow.