Skip to content
Tracon

WebhookUrlValidator

Namespace Tracon · Assembly Tracon.Core.dll

Validates webhook target addresses against SSRF.

public static class WebhookUrlValidator

objectWebhookUrlValidator

object.GetType(), object.MemberwiseClone(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()

The webhook subsystem’s biggest security risk. The webhook address is given by the user, and the server sends a request to that address. If left uncontrolled, it becomes a means of reaching internal-network services — including cloud metadata endpoints (169.254.169.254), which often hand out unauthenticated temporary credentials.

Defense layers:

  • Scheme: https only; http only for loopback and with explicit permission.
  • Address: DNS is resolved, private network ranges are rejected.
  • Rebinding: connects directly to the resolved IP, with the Host header preserved.
  • Redirects: not followed — a redirect is an escape route into a private network.

IsAllowedTarget(IPAddress, TraconWebhookOptions)

Section titled “ IsAllowedTarget(IPAddress, TraconWebhookOptions)”

Reports whether delivery to an address is allowed.

public static bool IsAllowedTarget(IPAddress address, TraconWebhookOptions settings)

address IPAddress

The resolved address.

settings TraconWebhookOptions

The webhook settings.

bool

true if a connection to the address can be made.

Loopback is accepted while TraconWebhookOptions.AllowInsecureHttp is enabled. That setting already means “this is a local development setup” and applies only to loopback targets. Otherwise, testing a local listener would require TraconWebhookOptions.AllowPrivateNetworkTargets, which opens the entire private network, including 10/8 and 169.254.169.254 — this would trade production security for development convenience.

No private range other than loopback is opened by that setting.

Reports whether an IP address falls within a private/local range.

public static bool IsPrivate(IPAddress address)

address IPAddress

The address.

bool

true if the address falls within a private range.

The rules live in EgressAddressValidator.IsPrivate, which all three outbound surfaces share. This member forwards to it and holds no copy of its own.

ToPolicy(TraconWebhookOptions, TraconEgressOptions?)

Section titled “ ToPolicy(TraconWebhookOptions, TraconEgressOptions?)”

Converts webhook settings into the shared egress address policy.

public static EgressAddressPolicy ToPolicy(TraconWebhookOptions settings, TraconEgressOptions? egress)

settings TraconWebhookOptions

The webhook settings.

egress TraconEgressOptions?

The shared egress settings, or null to consider only the webhook settings.

EgressAddressPolicy

The policy applied to webhook targets.

Both flags matter. TraconWebhookOptions.AllowPrivateNetworkTargets predates the shared TraconEgressOptions and stays honoured, so a setup that already opened the private network for webhooks keeps working. The shared option is read where the policy is built, in WebhookHttpClient and WebhookDeliveryJobHandler; either one being enabled is enough.

ArgumentNullException

settings is null.

ValidateFormat(string?, TraconWebhookOptions)

Section titled “ ValidateFormat(string?, TraconWebhookOptions)”

Validates an address by its scheme, without resolving DNS.

public static WebhookUrlVerdict ValidateFormat(string? url, TraconWebhookOptions settings)

url string?

The address to validate.

settings TraconWebhookOptions

The webhook settings.

WebhookUrlVerdict

The result. Rejects if the address format or scheme is invalid.

Used at save time (in the HTTP endpoint): DNS resolution would slow down the save, and the target may be unreachable at that moment. Real protection is applied at delivery time, with WebhookUrlValidator.ValidateResolvedAsync.

ValidateResolvedAsync(string?, TraconWebhookOptions, TraconEgressOptions, CancellationToken)

Section titled “ ValidateResolvedAsync(string?, TraconWebhookOptions, TraconEgressOptions, CancellationToken)”

Validates an address by resolving DNS and checking the IP range.

public static ValueTask<WebhookUrlVerdict> ValidateResolvedAsync(string? url, TraconWebhookOptions settings, TraconEgressOptions egress, CancellationToken cancellationToken = default)

url string?

The address to validate.

settings TraconWebhookOptions

The webhook settings.

egress TraconEgressOptions

The shared egress settings.

cancellationToken CancellationToken

The cancellation token.

ValueTask<WebhookUrlVerdict>

The result. Carries the resolved address if allowed.

Called at delivery time. The returned WebhookUrlVerdict.ResolvedAddress must be used when establishing the connection; resolving the address again opens the door to a DNS rebinding attack.