class WebhookTagger

Overview

Flags inbound webhook / callback endpoints — routes that receive server-to-server notifications from third parties (payment providers, VCS hosts, CI, messaging platforms). They warrant scrutiny for signature verification, replay protection, and source-IP trust, and the handlers often make outbound requests (SSRF surface).

Defined in:

tagger/taggers/webhook.cr

Constant Summary

AUTH_CALLBACK_SEGMENTS = Set {"oauth", "oauth2", "openid", "oidc", "auth", "authentication", "sso", "saml", "login", "signin"}

OAuth / OIDC / SSO authorization-code callbacks (/oauth/callback, /auth/<provider>/callback) are browser-redirect handlers, not inbound webhooks — but they share the generic callback path word and can arrive as a POST, so they were being mis-tagged. When callback is the only webhook signal and one of these auth segments is present in the path, suppress it. A genuine payment IPN at /payments/callback carries no auth segment and still tags.

CALLBACK_PARTS = Set {"callback", "callbacks"}
MEDIUM_PATH_PARTS = Set {"hook", "hooks", "callback", "callbacks", "notify"}

Weaker path segments shared with non-webhook routes. Require a POST (or other write) method before flagging on these alone.

notification(s) are intentionally excluded: an in-app notifications resource (POST /api/notifications, DELETE /notifications/{id}) is far more common than a notification webhook, and it is a write, so the method gate doesn't help. The verb form notify is kept — it is the canonical callback term for payment IPNs (notify_url).

READ_ONLY_METHODS = Set {"GET", "HEAD", "OPTIONS"}

Webhooks are delivered as non-GET requests. Gate the weaker path signals on "not a read", which — unlike an explicit POST/PUT/PATCH allow-list — also covers wildcard ("ANY"/"*") and blank methods that several analyzers emit for catch-all routes.

SIGNATURE_HEADERS = Set {"x_hub_signature", "x_hub_signature_256", "x_signature", "x_webhook_signature", "webhook_signature", "x_hook_signature", "x_event_key", "x_github_event", "x_gitlab_event", "x_gitlab_token", "stripe_signature", "paypal_transmission_sig", "x_razorpay_signature", "x_paystack_signature", "x_square_hmacsha256_signature", "x_slack_signature", "x_line_signature", "x_zm_signature", "x_signature_ed25519", "x_telegram_bot_api_secret_token", "x_shopify_hmac_sha256", "x_shopify_topic", "x_wc_webhook_signature", "x_wc_webhook_topic", "x_twilio_signature", "x_twilio_email_event_webhook_signature", "x_amz_sns_message_type", "x_mandrill_signature", "svix_id", "svix_signature", "svix_timestamp"}

Provider-specific signature/event headers. Any one is a strong webhook indicator on its own.

STRONG_PATH_PARTS = Set {"webhook", "webhooks", "ipn"}

Unambiguous webhook path segments — one is enough.

Constructors

Instance Method Summary

Instance methods inherited from class Tagger

name : String name, perform(endpoints : Array(Endpoint)) : Array(Endpoint) perform

Constructor methods inherited from class Tagger

new(options : Hash(String, YAML::Any)) new

Constructor Detail

def self.new(options : Hash(String, YAML::Any)) #

[View source]

Instance Method Detail

def perform(endpoints : Array(Endpoint)) #

[View source]