Impulseye lets you add a channel and paste in a webhook URL — Discord, Slack, Teams, a generic endpoint of your own. That single text field is also, by definition, a place where a user can ask my server to make an HTTP request to anywhere they want. That's server-side request forgery (SSRF), and it's worth treating seriously even in a small product.
Why it matters
The threat isn't "a user sends themselves a webhook." It's that your server — sitting inside your own private network, often with access other requests don't have — is the one making the request. A malicious value in that field isn't asking your server to fetch a website; it's asking your server to reach into places an outside attacker normally couldn't reach directly: internal admin panels, cloud metadata endpoints, services on localhost, or anything else reachable from inside your infrastructure but not from the public internet.
Any server-side code path that accepts a user-supplied URL and then fetches it — webhooks, image proxies, "import from URL" features, link previews — inherits this risk by default. It's not specific to alerting tools. If your server fetches a URL a user gave it, this applies to you too.
The fix
This is well-trodden ground — OWASP has a dedicated SSRF prevention cheat sheet, and the shape of a real fix is consistent across implementations:
- Validate the destination, not just the format. A URL can be syntactically perfect and still resolve to an internal or reserved address. Checking "is this a valid URL" is not the same as checking "is this a safe destination."
- Resolve before you trust. A hostname's DNS resolution can point somewhere different at request time than it did at validation time. The address actually being connected to is what needs checking, not just the hostname string.
- Don't trust redirects blindly. A URL can validate cleanly and then redirect somewhere unsafe. Following redirects without re-validating the new destination reopens the same hole one hop later.
- Apply it at every entry point, not just the obvious one. If a URL can be set on creation, it can usually also be changed later through a different code path — an edit endpoint, a test button, a background job that re-reads stored settings. Every one of those needs the same validation, not just the first form a user sees.
None of this is exotic. It's the standard, published mitigation for a well-known bug class — which is exactly why there's no excuse for skipping it just because the feature looks as harmless as "paste your webhook URL here."
Hardest part
Writing the validation function wasn't the hard part. Finding every place a URL could enter the system was. A webhook URL can be set when a channel is created, changed when it's edited, and re-read whenever an alert actually fires — three separate code paths, only one of which is the obvious "add channel" form a security review would naturally focus on first. A guard on the creation endpoint alone would have left the other two wide open.
The actual takeaway: treating "where can this value be set" as a single question with one answer is the mistake. Any value that matters for security needs the same check applied everywhere it can enter or re-enter the system — not just at the entry point that's easiest to remember to guard.