Verify GitHub Webhook Payloads

Implement GitHub webhook payload verification using HMAC-SHA256. Learn GitHub's X-Hub-Signature-256 header format and secure verification patterns for CI/CD pipelines.

Implementation

Detailed Explanation

Verifying GitHub Webhook Payloads

GitHub uses HMAC-SHA256 to sign webhook payloads, sending the signature in the X-Hub-Signature-256 header. This allows your server to confirm that webhook events originate from GitHub and have not been modified in transit.

GitHub's Signing Format

When you configure a webhook secret in a GitHub repository or organization:

  1. Secret configuration: You set a secret string when creating the webhook
  2. Signature computation: GitHub computes HMAC_SHA256(secret, raw_body) for each delivery
  3. Header format: X-Hub-Signature-256: sha256=a3f2b8c1d4e5f6...
  4. Legacy header: X-Hub-Signature: sha1=... (HMAC-SHA1, deprecated)

Implementation Example

# Node.js verification
const crypto = require('crypto');

function verifyGitHubWebhook(secret, payload, signatureHeader) {
    const expected = 'sha256=' +
        crypto.createHmac('sha256', secret)
              .update(payload, 'utf8')
              .digest('hex');

    return crypto.timingSafeEqual(
        Buffer.from(signatureHeader),
        Buffer.from(expected)
    );
}

Key Differences from Stripe

Unlike Stripe, GitHub's scheme:

  • No timestamp in signature: GitHub does not include a timestamp in the signed payload. Replay protection must be handled separately (e.g., via delivery IDs).
  • Simple format: The signature is always sha256= followed by the hex-encoded HMAC. No parsing of multiple fields is needed.
  • Delivery ID: GitHub includes X-GitHub-Delivery header with a unique UUID for each delivery, which you can store to detect replays.
  • Event type: The X-GitHub-Event header identifies the event type (push, pull_request, etc.) but is not included in the signature — it should not be trusted without verifying the payload.

Securing CI/CD Pipelines

GitHub webhooks are commonly used to trigger CI/CD pipelines:

  1. Always verify signatures before triggering builds or deployments
  2. Validate the event type by checking the parsed payload (not just the header)
  3. Restrict branch patterns — do not blindly deploy from any branch mentioned in a webhook
  4. Log delivery IDs for audit trails and replay detection
  5. Use separate secrets for different webhook endpoints (production vs staging)

Migration from SHA-1

GitHub still sends the X-Hub-Signature header (HMAC-SHA1) for backward compatibility, but all new implementations should use X-Hub-Signature-256. If you are maintaining an older integration, updating is straightforward — change sha1 to sha256 in both the HMAC computation and the header comparison.

Use Case

GitHub webhook verification is essential for CI/CD pipelines, automated code review bots, deployment automation, issue tracking integrations, and any system that reacts to repository events like pushes, pull requests, or releases.

Try It — HMAC Generator

Open full tool