Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Constrain webhook subscription URLs to prevent SSRF from user-supplied endpoints

Open
#280 1 comment 0 reactions 0 assignees View on GitHub

@Ranjeet2063 is already working on this.

Since Oct 9, 2026.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
22/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
nodejs, typescript
Domain
backend, security

Research direction

Start by reading src/infrastructure/webhooks/webhook-subscription.service.ts to see whether any URL validation exists, then trace the outbound request in webhook-delivery.service.ts. Registration and delivery both need IP-range checks on the resolved address, and redirects must be disabled or re-validated. Done means the listed SSRF cases have tests, but the issue says the module has no tests yet and the ownership fix is tracked separately.

Written by the indexing model from the issue text.

Description

advanced help wanted security

Problem

src/infrastructure/webhooks/ lets a subscriber register an endpoint that the API will later POST to. The module has five services, none tested:

  • webhook-subscription.service.ts — presumably stores the target URL
  • webhook-delivery.service.ts — performs the outbound request
  • webhook-processor.service.ts, webhook-event.service.ts, webhook-hmac.service.ts

And the controller that accepts registrations (webhook.controller.ts) hardcodes const userId = "system" at eight sites — lines 53, 65, 76, 89, 100, 110, 127, and 196 — meaning subscription ownership is not enforced either.

If the stored URL is not validated, an authenticated user can register an endpoint pointing at internal infrastructure and the API will dutifully request it, with retries and error logging that confirm reachability.

Why it matters

This is textbook SSRF. Targets include cloud metadata endpoints (169.254.169.254), internal admin services, and the database host. The retry logic makes it worse — repeated attempts are how SSRF scanners distinguish a filtered host from a closed port.

axios is a dependency and @nestjs/axios is present, so the outbound mechanism exists; the question is what validation happens before it.

Suggested Direction

  1. Verify the current state first. Read webhook-subscription.service.ts and confirm whether any URL validation occurs. If a scheme/host allowlist already exists, this issue shrinks to tightening it.
  2. Validate at registration time, not at delivery time — reject obviously dangerous destinations up front:
    • Scheme allowlist: https only (plus http explicitly for development), rejecting file:, gopher:, ftp:, data:.
    • Resolve the hostname and reject private, loopback, link-local, and unique-local ranges — 127.0.0.0/8, 10/8, 172.16/12, 192.168/16, 169.254/16, ::1, fc00::/7.
    • Reject non-standard ports unless explicitly configured.
  3. Re-resolve and re-check at delivery time. DNS rebinding defeats validation done only at registration: a hostname that resolved to a public address can resolve to 127.0.0.1 when the webhook fires. This is the part most implementations miss.
  4. Disable redirect following on the outbound client, or re-validate each hop — a 302 to an internal address bypasses the check entirely.
  5. Fix the ownership problem too: with userId = "system", any user can read or overwrite any other user's subscriptions, which is both a data leak and a way to redirect someone else's webhooks. That is tracked in a separate issue; note the dependency here.
  6. Add response-code and timing hygiene — avoid logging full response bodies from user-supplied endpoints, and apply the rate limiter to outbound delivery.

Constraints

  • Naive string checks on the URL (includes("127.0.0.1")) are trivially bypassed (http://127.1/, http://0x7f000001/, decimal IPs, DNS rebinding). Use proper IP-range checking on the resolved address.
  • Some users legitimately need internal webhooks in development. Make the strict policy the default with an explicit, documented opt-out for non-production.
  • This module has zero tests today — the webhook test issue should land first or alongside.

Acceptance Criteria

  • Only https (and http in development) schemes are accepted.
  • Hostnames resolving to private, loopback, or link-local addresses are rejected at registration and at delivery.
  • Redirects are not followed blindly, or each hop is re-validated.
  • Tests cover metadata-IP, loopback, private-range, redirect-to-internal, and DNS-rebinding cases.
  • Ownership is enforced so a user cannot register a webhook against another user's account.
  • Outbound delivery is rate-limited and does not log full response bodies.
Dominant language
TypeScript
Stars
7
Forks
55
Avg merge
1d 17h
Merged PRs (30d)
5

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from SourceXXL/alian_structure-api

All issues in SourceXXL/alian_structure-api

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.