Webhook Payloads Contain More Sensitive Data Than You Think
The headers and bodies of incoming webhooks often include credentials, customer data, and signature secrets. What to be careful about, and how to keep it under control.
When you think about webhook security, signature verification usually comes to mind first. Verify the HMAC, reject anything that doesn't match, move on. That part is well-documented and straightforward to implement.
What gets less attention is the data that arrives alongside the signature: the headers, the payload body, and where all of it ends up.
What's in a typical webhook payload
A Stripe payment_intent.succeeded event includes the full PaymentIntent object. That object contains:
- Customer ID and email
- Billing name and address
- Last four digits of the card (and sometimes more depending on your settings)
- Invoice and subscription IDs
- Any metadata you've attached to the payment
A GitHub push event includes commit messages, author names, email addresses, and file paths. Shopify order webhooks include shipping address, line items, and customer contact details.
None of this is surprising. The point of a webhook is to tell you what happened, and what happened usually involves real data about real people. But it means every webhook event your system receives is carrying data that has privacy and compliance implications.
The header problem
The payload body gets most of the attention, but headers deserve equal scrutiny.
Every webhook arrives with a signature header: Stripe-Signature from Stripe, X-Hub-Signature-256 from GitHub, X-Shopify-Hmac-SHA256 from Shopify. These don't contain your signing secret. What they do contain is the computed HMAC signature for that specific request, which is worth keeping out of logs and dashboards.
Beyond signature headers, webhooks sometimes arrive with authorization tokens, API keys, or session credentials, especially from internal services or custom integrations that use standard HTTP auth patterns. An Authorization: Bearer <token> header in a webhook from your own infrastructure is a real credential that should not be visible to every team member with dashboard access.
Where webhook data ends up
The chain is longer than it looks:
- Your application receives the event and stores it (possibly the full payload)
- Your error monitoring tool captures request context on exceptions, including headers
- Your logging infrastructure records incoming requests, possibly with bodies
- Your webhook monitoring dashboard stores events for inspection and replay
- Team members with dashboard access can view those stored events
Each of these is a potential exposure point. Error monitoring tools like Sentry will, by default, capture request headers and body content when an exception occurs. If your webhook handler throws on a malformed payload and you haven't configured scrubbing, those headers, including any credentials, go to your error tracker.
Sentry's default behaviour includes request headers in error context. Configure beforeSend to scrub sensitive header values before they leave your server.
Practical controls
In your application:
- Store only what you need from the payload. If you don't need the full billing address, don't store it.
- Set up structured logging that explicitly excludes header values from request logs.
- Configure your error monitoring tool to scrub sensitive headers before sending events.
At the ingest layer:
If you're using a webhook monitoring tool, check whether it supports header masking. You want to be able to hide values like Authorization, Cookie, X-Api-Key, and signature headers in the event viewer without affecting delivery. The raw data needs to reach your destination, but it doesn't need to be readable in the dashboard.
Payload field masking is useful for JSON payloads where specific fields contain sensitive values. Targeting customer.email or data.card.last4 by path lets you keep the rest of the payload visible while hiding the parts that matter for privacy.
For provider signature headers specifically:
These don't need to be visible to developers debugging webhook behaviour. What matters for debugging is the verification result (verified/failed/skipped), not the raw signature value itself.
The goal isn't perfection
Webhook payloads contain real data. That can't be fully avoided without losing the usefulness of having events available for inspection and replay. The goal is proportionality: don't expose credentials and PII to more people or more systems than genuinely need them.
Most teams get there incrementally: verification first, then scrubbing in error monitoring, then masking in the tools where event data is visible. None of it requires a significant overhaul of how you work with webhooks.
Share this post
Webhook Watchtower
Stop debugging webhooks in logs.
Capture every event, replay failures, and get alerted when deliveries fail, without changing your existing setup.
Try it free →Related posts
Monitoring Webhook Health: The Metrics That Actually Matter
Uptime doesn't tell you whether webhooks are working. A short list of the signals that actually indicate a healthy webhook pipeline, and what each one catches that the others miss.
Alerting on Webhook Failures Without Alert Fatigue
Notify on every failed delivery attempt and you'll train people to ignore the channel. A pattern for alerting on what actually needs a human, and staying quiet about what doesn't.
IP Allowlisting vs Signature Verification: What Actually Secures a Webhook Endpoint
IP allowlisting feels like a solid first line of defence for a webhook endpoint. It isn't, and understanding why makes the case for signature verification much clearer.