Webhook Security Signatures and Secrets
Level: advanced · ~15 min read · Intent: informational
Key takeaways
- A webhook endpoint should never trust inbound requests blindly. Verification is what separates a real platform delivery from any random POST sent to your public URL.
- GitHub's docs explicitly recommend using a webhook secret, validating the signature before processing, and keeping secrets out of payload URLs.
- Strong webhook security is not just about HMAC comparison. It also includes HTTPS, fast acknowledgement, secret storage, duplicate handling, and narrow event subscriptions.
- The safest receiver pattern is: verify the signature, reject invalid deliveries, acknowledge quickly, then do heavier work in background processing.
References
FAQ
- What is a webhook secret?
- A webhook secret is a shared value known by both the source platform and your receiver. The platform uses it to create a signature, and your receiver uses the same secret to verify that the delivery is authentic and was not tampered with.
- What is a webhook signature?
- A webhook signature is a cryptographic hash attached to a delivery, usually in a request header. Your receiver computes its own expected signature using the shared secret and compares it to the one sent by the platform.
- Why is HTTPS not enough for webhook security?
- HTTPS protects the transport, but it does not prove that the sender is really the platform you expect. Signature validation helps verify authenticity and payload integrity.
- Can I put a secret in the webhook URL?
- You should avoid that. GitHub explicitly warns against putting secrets or API credentials in webhook URLs. Use webhook secrets and signature validation instead.
The moment you expose a webhook endpoint to the public internet, you create a simple but serious question:
How do you know the inbound request really came from the platform you trust?
If you do not answer that carefully, your automation may process:
- forged requests
- replayed payloads
- tampered event bodies
- noisy malicious traffic
- accidental test traffic as if it were production data
That is why webhook security is not optional glue work.
It is the trust boundary for event-driven automation.
The first rule: a webhook URL is not proof
It is easy to treat a webhook endpoint like a secret tunnel:
- the platform knows the URL
- the URL is obscure
- therefore the traffic must be valid
That is not a safe assumption.
GitHub's validating-webhook-deliveries docs are explicit: once your server is listening for deliveries, you should validate the webhook signature before processing the delivery further, so you can confirm it came from GitHub and was not tampered with.
That is the baseline mindset:
an inbound POST is just an inbound POST until you verify it.
What a webhook secret actually does
A webhook secret is a shared value configured in both places:
- on the platform sending the webhook
- on the system receiving the webhook
The platform uses that secret to generate a cryptographic signature over the payload. Your receiver uses the same secret to compute its own expected signature.
If the two match, you have stronger reason to trust that:
- the payload came from the expected sender
- the body was not modified in transit
That is why secrets matter.
They are not just passwords for setup screens. They are part of request verification.
What a webhook signature actually is
A webhook signature is usually sent in a request header.
GitHub documents this clearly: the hash signature appears in the X-Hub-Signature-256 header.
Your job as the receiver is to:
- read the raw request body
- compute the expected hash using the shared secret
- compare it to the received signature
- reject the request if they do not match
That comparison should happen before you do meaningful processing.
Not after.
Why HTTPS is necessary but not sufficient
HTTPS is essential because it protects transport.
But HTTPS alone does not prove sender authenticity.
You still need verification because:
- someone can send their own HTTPS request to your public endpoint
- a correct TLS connection does not prove the sender is the platform you expect
- transport protection is different from payload authenticity
So the practical rule is:
- use HTTPS for transport
- use secrets and signatures for authenticity
You usually need both.
GitHub's most useful webhook security advice
GitHub's docs are especially good here because they combine verification advice with operational guidance.
The most useful points are:
Use a webhook secret
GitHub explicitly says to use a webhook secret instead of putting sensitive information in the payload URL.
That matters because URLs get copied, logged, and leaked more easily than people think.
Store the secret securely
GitHub explicitly says never to hardcode the token into an application or push it to a repository.
That is not GitHub-specific advice. It is good webhook hygiene in general.
Respond quickly
GitHub's best-practices docs say your server should respond with a 2XX within 30 seconds of receiving a delivery.
The practical implication is:
- verify first
- acknowledge quickly
- do heavier downstream work later
Keep handling logic narrow
GitHub recommends subscribing only to the events you need.
That is a security and reliability win.
Less irrelevant traffic means:
- less noise
- less processing surface
- fewer chances to mishandle unexpected events
The safest webhook receiver pattern
For most automations, the safest receiver pattern looks like this:
- Receive the request over HTTPS.
- Read the raw body exactly as sent.
- Validate the signature using the shared secret.
- Reject invalid deliveries immediately.
- Check the event type and decide whether it matters.
- Acknowledge quickly with a
2XXif valid. - Queue or background the heavier processing.
- Log delivery IDs and outcome for troubleshooting.
This is much safer than:
- parsing first and verifying later
- processing inline before validation
- assuming the source would never send bad input
Common security mistakes teams make
Mistake 1: Putting secrets in the URL
GitHub explicitly warns against this.
Query strings and URLs are more likely to appear in:
- logs
- dashboards
- analytics
- screenshots
- copied config docs
Use a proper webhook secret instead.
Mistake 2: Hardcoding secrets in code
This increases leak risk and makes rotation harder.
Mistake 3: Verifying after processing
If you validate only after business logic starts, you have already trusted an unverified sender.
Mistake 4: Ignoring duplicate or replay behavior
Security and reliability overlap here.
If a delivery is replayed or duplicated, can your system detect and handle it safely?
Mistake 5: Taking too long to respond
GitHub's docs note that slow receivers can cause failures. If the sender gives up, the event may need retry or redelivery handling.
Mistake 6: Treating webhook security as only a crypto problem
The HMAC check matters, but so do:
- secret storage
- event filtering
- background processing
- delivery logging
- failure recovery
Signature validation is only the start
Even with signature validation, your receiver still needs operational discipline.
Event filtering
Do not process everything blindly.
Delivery tracking
GitHub's webhook docs provide delivery logs and redelivery patterns for a reason.
Failure handling
GitHub's failed-delivery docs make clear that failures happen and need operational recovery.
Idempotency
If the same valid event arrives twice, the system should not create twice the damage.
That is why webhook security and idempotency belong close together in the course.
When teams under-secure webhooks
This usually happens for one of three reasons:
1. The workflow started as a quick internal experiment
The endpoint becomes "temporary" and then quietly stays in production.
2. The platform abstracted too much
A no-code builder hides some complexity, so people assume the verification problem disappeared.
3. The team focused only on success-path speed
They optimized for "did the event arrive?" instead of "can we trust this event?"
Those are all understandable mistakes. They are still mistakes.
The practical rule to remember
Treat every inbound webhook like an untrusted request until proven otherwise.
That means:
- secret configured
- signature verified
- HTTPS enforced
- event filtered
- delivery logged
- processing deferred after acknowledgement when needed
If you do those things consistently, webhook security stops being mysterious.
It becomes a repeatable receiver pattern.
That is exactly what strong workflow automation programs need.
About the author
Elysiate publishes practical guides and privacy-first tools for data workflows, developer tooling, SEO, and product engineering.