Skip to content

fix(webhooks): drop the AgentMail-specific webhook body cap - #6436

Merged
waleedlatif1 merged 1 commit into
stagingfrom
review/agentmail-webhook-audit
Aug 8, 2026
Merged

fix(webhooks): drop the AgentMail-specific webhook body cap#6436
waleedlatif1 merged 1 commit into
stagingfrom
review/agentmail-webhook-audit

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Follow-up audit of #6431. The receiver carried its own 4 MB body cap, justified on the grounds that it is the only public receiver that parses an unverified body before authenticating.

That justification was wrong. app/api/webhooks/trigger/[path]/route.ts calls parseWebhookBody (which JSON.parses up to the shared cap) well before verifyProviderAuth, on an equally public path. The AgentMail receiver has the same exposure profile as its sibling, so a separate, tighter cap was an inconsistent limit rather than a principled one — and it could reject a large-but-legitimate email outright, which the shared cap would have accepted.

Removing it costs nothing security-wise: the one-signature-check-per-request property comes from the tenant lookup and its unique index, not from the body cap. This also removes the only backwards-incompatible behavior change in #6431 and avoids setting a per-provider-constant precedent in a shared module.

Also documents why the routing id is bounded at 320 characters (RFC 5321 max address length, since an AgentMail inbox id is an email address) so it doesn't read as arbitrary.

Audit findings that needed no change

  • Only two writers of workspace.inbox_provider_id (enableInbox sets a freshly minted id, disableInbox nulls it), so the unique index cannot be violated by any existing flow.
  • No webhook rows with a null provider id, so the routing lookup cannot strand an existing tenant.
  • The enable-path race is unchanged. Between the webhook row insert and the workspace update, the old code verified the signature and then failed its inboxProviderId mismatch check; the new code fails the lookup. Both return 401 and both rely on provider retry.
  • The partial index is used for a bare equality predicate — verified with EXPLAIN against an existing WHERE col IS NOT NULL partial index on the same server, which plans an index scan without the query restating the predicate.

Testing

Existing suites pass (620 across webhooks/mothership). The body-cap test now asserts the route rejects an oversized body before reaching either the database or the hash. Type-check, lint, check:api-validation, and check:migrations pass.

The receiver had its own 4 MB cap on the grounds that it is the only one
that parses an unverified body before authenticating. It is not — the
generic path receiver parses at the shared cap well before verifying auth,
so the tighter limit was inconsistent rather than principled, and it could
reject a large-but-legitimate email outright. The one-signature-check-per
-request property comes from the tenant lookup and its unique index, not
from the cap.

Also records why the routing id is bounded at 320 characters.
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 8, 2026 8:31pm

Request Review

@cursor

cursor Bot commented Aug 8, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Aligns an inconsistent lower cap with existing shared webhook limits; behavior change is accepting larger legitimate payloads, not weakening auth or parsing gates.

Overview
Removes the 4 MB AgentMail-only body limit and applies the shared WEBHOOK_MAX_BODY_BYTES cap (default 10 MB) for content-length checks, stream reads, and 413 logging on the AgentMail receiver, matching other public webhook routes.

Deletes AGENTMAIL_WEBHOOK_MAX_BODY_BYTES from constants.ts so webhook sizing stays a single source of truth. The oversized-body test now uses the shared cap and asserts 413 with no DB lookup or signature verification.

Clarifies agentMailRoutingSchema docs and the inbox_id max(320) error message as RFC 5321 max email address length, since AgentMail inbox ids are addresses.

Reviewed by Cursor Bugbot for commit 7f2aba0. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR removes AgentMail’s provider-specific 4 MiB webhook limit and applies the shared webhook body cap instead.

  • Updates the AgentMail receiver and oversized-body test to use WEBHOOK_MAX_BODY_BYTES.
  • Removes the unused AgentMail-specific limit constant.
  • Documents the RFC-derived 320-character routing identifier bound and adds a descriptive validation message.

Confidence Score: 5/5

The PR appears safe to merge because the AgentMail receiver consistently adopts the existing bounded shared webhook limit and no concrete regression remains.

The changed route preserves both Content-Length and streaming enforcement, continues to reject bodies above the configured shared cap before database or signature work, and removes an export with no remaining consumers.

Important Files Changed

Filename Overview
apps/sim/app/api/webhooks/agentmail/route.ts Replaces the AgentMail-specific body cap with the shared webhook limit consistently across header and streaming checks.
apps/sim/app/api/webhooks/agentmail/route.test.ts Updates the oversized-body test to exercise the shared cap and confirms rejection occurs before database lookup or signature verification.
apps/sim/lib/api/contracts/webhooks.ts Documents the routing identifier’s RFC-derived bound and adds a clearer maximum-length validation error.
apps/sim/lib/webhooks/constants.ts Removes the now-unused AgentMail-specific body-limit export without leaving repository consumers.

Sequence Diagram

sequenceDiagram
  participant Sender as AgentMail
  participant Route as AgentMail webhook route
  participant Limit as Shared body-limit helpers
  participant DB as Workspace lookup
  participant Svix as Signature verifier
  Sender->>Route: POST webhook
  Route->>Limit: Enforce WEBHOOK_MAX_BODY_BYTES
  Limit-->>Route: Bounded raw body
  Route->>Route: Parse routing inbox_id
  Route->>DB: Find workspace by inbox provider id
  DB-->>Route: Workspace secret
  Route->>Svix: Verify one signature against raw body
  Svix-->>Route: Verified payload or rejection
Loading

Reviews (1): Last reviewed commit: "fix(webhooks): drop the AgentMail-specif..." | Re-trigger Greptile

@waleedlatif1
waleedlatif1 merged commit 0b016c2 into staging Aug 8, 2026
24 checks passed
@waleedlatif1
waleedlatif1 deleted the review/agentmail-webhook-audit branch August 8, 2026 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant