Skip to main content

Is a Slack webhook URL a secret?

Yes. A Slack incoming webhook URL is a credential, not just an address. The token in its path is the only thing authenticating the request, so anyone holding the URL can post messages into that channel with no further check. Slack documents it as a secret and tells you to delete it if it is exposed.

Sending webhooks?
Svix is the enterprise-ready webhook sending service. It handles signing, retries, and delivery observability, so you can ship a reliable webhook platform in minutes instead of months. Start sending webhooks with Svix.

What the URL actually authorizes

A Slack incoming webhook URL looks like https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX. There is no API key header, no OAuth token, and no signature to compute. You POST a JSON body and Slack posts it in the channel. The three path segments identify the workspace, the app's webhook configuration, and a random token, and possession of that string is the entire authorization model. This is what people mean by a bearer credential: the credential is the URL.

That makes it different from the webhook secret a webhook provider gives you for verifying inbound deliveries. A secret proves a request came from a particular sender and never travels in the request itself. A Slack webhook URL travels in every request, sits in your configuration, and does its own authorizing.

What someone with the URL can and cannot do

The blast radius is narrower than it first looks, which is worth knowing before you decide how much to worry.

Someone with a leaked URL can post messages into exactly one channel, under your app's name and icon. They cannot read messages, list channels, act on behalf of a user, or reach any other part of the workspace. A webhook created through a Slack app also ignores channel, username, and icon_emoji fields in the payload, so an attacker cannot redirect the message elsewhere or impersonate a person. See are Slack webhooks deprecated? for why older legacy integrations behaved differently and could be redirected.

Write access to one channel is still worth defending. Most webhooks post to a channel a team already trusts: deploy notifications, alerting, on-call escalation. A convincing fake "production deploy failed, run this rollback command" message in an alerts channel is a phishing vector that arrives with the visual authority of your own tooling. The other common outcome is simple noise, where a scraper finds the URL and floods the channel until someone revokes it.

Where these URLs leak

The URL leaks the way credentials always leak. It gets committed to a repository inside a config file or a CI workflow. It gets pasted into a ticket or a chat thread while someone debugs an integration. It gets embedded in a browser bundle or a mobile app so a client can post directly, which ships the credential to every user who opens developer tools. It ends up in a screenshot of a settings page.

Server-side logging is the case people miss. If the URL is the request target, it appears in outbound request logs, error traces, and any APM tool recording full URLs. Store it in a variable your logger redacts rather than inlining the literal.

Storing and rotating the URL

Treat it as you would a database password. Keep it in a secrets manager or an environment variable, restrict which services can read it, and keep it out of version control and out of any code that runs in a browser or on a phone. Where a client genuinely needs to trigger a Slack message, put your own authenticated endpoint in front and let your server hold the URL.

Slack has no rotate button for incoming webhooks. Rotation means opening the app's Incoming Webhooks page, deleting the compromised webhook, and adding a new one to the workspace, which produces a different URL you then swap into your configuration. Our guide to getting a Slack webhook URL walks through those screens. Because each URL is bound to one channel, one leaked URL only forces one rotation, which is a good reason to use a separate webhook per channel rather than routing everything through one.

Why Slack signs the other direction

Slack does not treat every webhook this way. When Slack sends events to your server through the Events API, it signs each request: an X-Slack-Request-Timestamp header and an X-Slack-Signature header holding v0= followed by an HMAC-SHA256 over the string v0:{timestamp}:{body}, computed with your app's signing secret. You recompute it and reject anything that does not match or whose timestamp is more than five minutes old.

That is the difference between a URL you keep quiet and a webhook signature you verify. Secrecy fails the moment the string is copied anywhere. A signature keeps working even if the endpoint URL is public knowledge, because the proof is computed per request and a replay is caught by the timestamp. If you are the one sending events to customers rather than posting into a channel, sign them: Svix provides signing, retries, and per-endpoint delivery logs so your customers never have to treat a URL as a password.

Frequently asked questions

Can I put a Slack webhook URL in a public repository?

No. Anyone who finds it can post to that channel. If one has already been pushed, rewriting history is not enough, because the URL may already be indexed. Delete the webhook in the app settings and add a new one.

Do Slack webhook URLs expire on their own?

No. A webhook URL keeps working until you delete it, remove the app, or the app loses access to the workspace. There is no built-in expiry, so a leaked URL stays valid until someone revokes it.

Can someone read my Slack messages with a webhook URL?

No. Incoming webhooks are write-only and bound to a single channel. The URL allows posting into that channel and nothing else: no reading history, no listing channels, no acting as a user.

How do I rotate a Slack webhook URL?

Open api.slack.com/apps, select the app, go to Incoming Webhooks, delete the old webhook, and click "Add New Webhook to Workspace" to generate a replacement. Update your configuration with the new URL before deleting the old one if you cannot afford a gap.

Ready to send webhooks?

Svix handles signing, retries, rate limiting, and delivery observability for the webhooks you send to your users, so your team can stay focused on your product.