Skip to content

Add rate limiting, payload size limits, and structured rejection logging to the webhook endpoint #260

Description

@Lakes41

Difficulty: Advanced
Type: Security

Background
The dashboard exposes a webhook endpoint that verifies x-guildpass-signature using @guildpass/webhook-utils before processing events like member.joined and pass.activated. The webhook-utils README's security best-practices section covers signature and secret handling, but says nothing about protecting the endpoint itself from abuse (flooding, oversized payloads, or scripted probing of the signature-verification logic).

Problem
An unauthenticated (pre-signature-check) request to the webhook endpoint currently has no request-size ceiling or rate limit ahead of the cryptographic verification step, meaning a malicious or misbehaving client could send excessively large bodies or a high volume of invalid-signature requests, consuming CPU on repeated HMAC computations and buffering large payloads before rejection — and there's no structured log trail to distinguish "someone is probing this endpoint" from ordinary transient failures.

Expected outcome
The webhook route rejects oversized request bodies before attempting signature verification, applies a sensible rate limit per source IP (or another available signal) for repeated invalid-signature attempts, and logs rejections in a structured format (reason, timestamp, source, but never the secret or a valid signature value) suitable for later alerting.

Suggested implementation

  • Add a body-size guard (e.g. reject bodies over a configurable limit, such as 256KB, with a 413 before parsing/verifying).
  • Add a lightweight in-process (or storage-backed, reusing Issue Add timeout support to IntegrationClient #8's abstraction) rate limiter keyed by source IP + endpoint, returning 429 once a threshold of invalid-signature attempts is exceeded within a window.
  • Emit structured log entries (JSON) for every rejection with a reason enum (oversized_payload, invalid_signature, expired_timestamp, rate_limited, malformed_header) — reusing/extending the existing error categories already returned by verifySignature.
  • Document the new limits and log format in SECURITY.md and packages/webhook-utils/README.md's "Security Best Practices" section (cross-referenced, since the limiting logic likely lives in the dashboard's route, not the package itself).

Acceptance criteria

  • Requests over the configured size limit are rejected before signature verification runs, with a clear status code.
  • Repeated invalid-signature attempts from the same source within a window trigger rate limiting.
  • Rejections are logged in a consistent structured format without ever logging the raw secret or a valid signature.
  • Legitimate webhook traffic at normal volume is unaffected (tests demonstrate the limiter doesn't trigger under expected load).
  • pnpm --filter @guildpass/dashboard test passes, including new tests for size limiting and rate limiting.

Likely affected files/directories
Webhook route handler (apps/dashboard/app/api/webhook*/), SECURITY.md, packages/webhook-utils/README.md, new rate-limiting utility module.

Metadata

Metadata

Assignees

Labels

GrantFox OSSGrantFox Open Source Sponsorship program tagMaybe RewardedIssue may qualify for a reward upon successful completion per campaign rulesOfficial Campaign | FWC26Official FWC26 campaign issue — eligible for campaign scoring and rewardsdashboardAutomatically createdhelp wantedExtra attention is neededsecuritySecurity-related fix, hardening, audit, or vulnerability remediation

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions