An unset webhook secret did not close my endpoint, it opened it

by

A two minute check for anyone who receives signed webhooks. Find the line where your code reads the signing secret from the environment. Then find out what happens to a request when that variable is not set at all.

I expected the answer to be that everything fails. That is what a missing secret sounds like: no key, so no signature can match, so every event is refused, and the worst case is a noisy outage somebody notices within the hour.

It is not what happens. An unset variable arrives in most config layers as an empty string, and an empty string is a perfectly valid key to a hash function. The official library I use takes the secret, computes the expected signature with it, and compares. It never asks whether the key is empty. So with no secret configured, the endpoint does not refuse everything. It accepts anything signed with the one key every person on earth knows, which is nothing at all.

That turns a missing line in a deployment file into a way to send my system a forged payment confirmation, with a signature that verifies.

It became likely rather than theoretical when I split one webhook endpoint into two, each with its own secret, and renamed the variables. An upgrade that does not edit its environment lands with both new names unset. Every test passes, because the tests set the secrets. The failure only exists on a server whose config file is one change behind the code.

The fix is three lines: if the secret is empty, refuse before verifying. The part that took thought was the status code. A bad signature is answered as a client error, because the request is what is wrong. A missing secret is my fault and is fixed by one line of config, so it answers as a server error and logs which variable is empty. The sender keeps the events and the alert points at my side, not theirs.

The check for your own stack: unset the signing secret on a staging copy, sign a test payload with an empty key, send it, and see whether it is accepted. Do not reason about it from the docs. Read the function that verifies, which in my case was about fifty lines and never checked the key.

Which other settings in your stack fail open when they are empty rather than when they are wrong?

2 views

Add a comment

Replies

Be the first to comment