If you received an email from GitHub Security with the reference GH-9951654-7992-a1, your webhook secrets have been exposed. Here’s the rundown of what happened and what you actually need to do about it.
What Happened?
Between September 11, 2025 and January 26, 2026, a bug in GitHub’s webhook delivery platform caused webhook secrets to be included in an HTTP header called X-Github-Encoded-Secret on a subset of deliveries. The header was never meant to be there, it was a side effect of a new version of the delivery platform being gradually feature flagged out.
The bug was present from September through to December 10, 2025, and then briefly reappeared on January 5, 2026. It was permanently fixed on January 26.
The secret was encoded in base64, not encrypted or hashed. So if any system receiving your webhooks was logging full request headers during that window, the secret is potentially sitting in your logs in a format that’s trivially reversible.
GitHub confirmed the deliveries were over TLS, meaning nobody in transit could read the header. And they’ve found no evidence of external compromise. That said, you still need to act, TLS just means it wasn’t intercepted in transit. Whether it ended up in logs is a different question entirely.
Why It Matters
Webhook secrets exist purely to let you verify that a delivery genuinely came from GitHub. They’re used to compute the X-Hub-Signature-256 HMAC signature on each delivery, and if you’re doing this properly your receiving end checks that signature before acting on the payload.
If someone has your webhook secret, they can forge webhook payloads that pass signature verification. What that means in practice depends entirely on what your webhook triggers, anything from CI pipelines to deployment hooks to third party integrations.
What You Need to Do
1. Rotate Your Webhook Secrets
Go through each affected webhook and generate a new secret. You’ll need to update it on the GitHub side and in any receiving system that uses it to verify signatures. GitHub’s email should have included a list of the specific repos and hook IDs affected.
If you’ve got a lot to deal with, I’ve put together bulk rotation and audit scripts on the incident documentation page using the GitHub CLI. A fair bit faster than clicking through the UI twenty million times.
Docs: https://docs.github.com/en/webhooks/using-webhooks/editing-webhooks
2. Check for Logged Headers
Any system that sits in front of your webhook receiver and logs HTTP request headers is worth checking. The usual spots:
- Your webhook receiver application logs
- API gateways (AWS API Gateway, Kong, NGINX access logs with
$http_*variables) - Observability platforms — Datadog, New Relic, Sentry, etc.
- Reverse proxies in front of the receiver
Look for X-Github-Encoded-Secret specifically. If you find it, purge the relevant log entries or restrict access to them.
3. Verify Signature Validation
Once you’ve rotated, it’s worth double checking the receiving end is actually validating signatures with the new secret. If this wasn’t wired up properly before, now’s a good time to fix it.
Docs: https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries
Note: if the affected webhook or its repository has already been deleted, you can skip it — no action needed for those.
GH CLI Commands
Rather than clicking through the GitHub UI for each webhook, the docs page has a handful of GH CLI commands to help with this at scale. Bulk auditing across all your repos, bulk secret rotation with a CSV output for tracking, and bulk deletion for any redundant webhooks you might as well clean up while you’re at it.
For context, I had a fair few repository webhooks flagged across personal repos and went through the rotation process in a few minutes using the CLI instead of hours via the UI.