GitHub Webhooks - Reference

Cheatsheet Git

Security headers, events, testing, and setup guide for GitHub webhooks

Security Headers

GitHub sends these headers with each webhook request.

HeaderDescription
X-GitHub-EventEvent type (push, pull_request, etc.)
X-Hub-Signature-256HMAC SHA-256 signature for verification
X-GitHub-DeliveryUnique delivery ID
User-AgentAlways starts with GitHub-Hookshot/

Signature Verification Steps

How to verify GitHub webhook signatures securely.

  1. Read raw request body
  2. Compute HMAC SHA-256 with your secret
  3. Compare with X-Hub-Signature-256 header
  4. Use constant-time comparison to prevent timing attacks

Why it matters:

  • Prevents unauthorized webhook calls
  • Ensures request is from GitHub
  • Protects against replay attacks

Common Events

GitHub webhook event types and their triggers.

EventTrigger
pushCode pushed to repository
pull_requestPR opened, closed, or updated
issuesIssue created or modified
releaseRelease published
workflow_runGitHub Actions workflow completed
createBranch or tag created
deleteBranch or tag deleted
forkRepository forked
starRepository starred
watchRepository watched

Event Payloads

Example payload structures for common events.

Push Event

{
  "ref": "refs/heads/main",
  "before": "abc123...",
  "after": "def456...",
  "repository": {
    "name": "my-repo",
    "full_name": "user/my-repo"
  },
  "pusher": {
    "name": "username",
    "email": "user@example.com"
  },
  "commits": [...]
}

Pull Request Event

{
  "action": "opened",
  "number": 42,
  "pull_request": {
    "title": "Fix bug",
    "state": "open",
    "user": {"login": "username"},
    "head": {"ref": "feature-branch"},
    "base": {"ref": "main"}
  }
}

Testing - ngrok

Expose local server for webhook testing.

# Install ngrok
# Download from https://ngrok.com/download

# Expose local server
ngrok http 3000

# Copy HTTPS URL to GitHub webhook settings
# Example: https://abc123.ngrok.io/webhook

Alternative: Use GitHub webhook delivery tab to redeliver past events

Testing - Manual cURL

Test webhook handler with cURL.

curl -X POST http://localhost:3000/webhook \
  -H "X-GitHub-Event: push" \
  -H "X-Hub-Signature-256: sha256=YOUR_SIG" \
  -H "Content-Type: application/json" \
  -d '{"ref":"refs/heads/main"}'

Generate valid signature:

echo -n '{"ref":"refs/heads/main"}' | \
  openssl dgst -sha256 -hmac "your_secret"

Testing - Payload Examples

Save test payloads for different events.

push-event.json:

{
  "ref": "refs/heads/main",
  "repository": {
    "name": "test-repo",
    "full_name": "user/test-repo"
  },
  "pusher": {
    "name": "testuser"
  }
}

Test with file:

curl -X POST http://localhost:3000/webhook \
  -H "X-GitHub-Event: push" \
  -H "Content-Type: application/json" \
  -d @push-event.json

Setup - GitHub Configuration

Configure webhook in GitHub repository.

Steps:

  1. Go to Settings → Webhooks → Add webhook
  2. Enter payload URL (HTTPS required in production)
  3. Set content type to application/json
  4. Generate and save secret token
  5. Select events to trigger

Payload URL examples:

  • Development: https://abc123.ngrok.io/webhook
  • Production: https://api.example.com/webhook

Setup - Secret Generation

Generate a secure webhook secret.

# Linux/Mac
openssl rand -hex 32

# Or use Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

# Or use Python
python3 -c "import secrets; print(secrets.token_hex(32))"

Setup Checklist

Complete setup checklist for production webhooks.

GitHub Settings:

  • Go to Settings → Webhooks → Add webhook
  • Enter payload URL (HTTPS required in production)
  • Set content type to application/json
  • Generate and save secret token
  • Select events to trigger

Code:

  • Implement signature verification
  • Add event type handling
  • Configure deployment script path
  • Set up error logging

Security:

  • Use HTTPS in production
  • Store secret in environment variable
  • Add rate limiting
  • Set proper file permissions on deploy script
  • Add IP allowlist (optional)

Production Tips

Best practices for production webhook deployment.

Run as Service:

# systemd (Linux)
sudo systemctl enable your-webhook.service

# PM2 (Node.js)
pm2 start app.js --name webhook
pm2 startup
pm2 save

Logging:

# Redirect to log file
exec >> /var/log/webhook.log 2>&1

Monitor:

  • Check GitHub webhook delivery tab for failures
  • Set up alerts for 4xx/5xx responses
  • Log all webhook payloads for debugging

GitHub IP Ranges

Optionally restrict webhooks to GitHub IPs.

Get current GitHub IP ranges:

curl https://api.github.com/meta | jq .hooks

Nginx allowlist:

location /webhook {
    allow 192.30.252.0/22;
    allow 185.199.108.0/22;
    allow 140.82.112.0/20;
    deny all;

    proxy_pass http://localhost:3000;
}

Troubleshooting - Failed Deliveries

Debug failed webhook deliveries.

Check GitHub:

  1. Go to Settings → Webhooks
  2. Click on webhook URL
  3. View “Recent Deliveries”
  4. Check response code and body

Common Issues:

  • Server not reachable (DNS, firewall)
  • Invalid SSL certificate
  • Signature verification failed
  • Server returning 500 error
  • Timeout (GitHub waits 10 seconds)

Troubleshooting - Signature Mismatch

Fix signature verification errors.

Checklist:

  • Using correct secret
  • Reading raw request body
  • Using SHA-256 (not SHA-1)
  • Comparing with X-Hub-Signature-256 header
  • Using constant-time comparison
  • Not double-parsing JSON

Debug tip:

# Log received signature and computed hash
echo "Received: $signature"
echo "Expected: $computed_hash"

Webhook Retries

GitHub automatically retries failed webhooks.

Retry behavior:

  • GitHub retries up to 3 times
  • Exponential backoff between retries
  • Stops after 3 consecutive failures

Best practices:

  • Return 2xx status code quickly
  • Process heavy work asynchronously
  • Implement idempotency (handle duplicate events)

Rate Limits

Webhook rate limits and quotas.

GitHub limits:

  • Max 1000 webhook deliveries per hour per repository
  • 10 second timeout per request
  • 5 MB max payload size

Your server:

  • Implement rate limiting on webhook endpoint
  • Queue webhooks for processing
  • Don’t block on long-running tasks