fix(whatsapp): require a write role on the WhatsApp write routes - #448
Merged
Conversation
The five write handlers under /api/whatsapp resolved the caller's
account_id straight off their profile row, which only proves account
membership — never a role. Every other write surface in the app
(account/, ai/, automations/, flows/, quick-replies/) already goes
through requireRole(); this family was missed.
RLS did not backstop it, because each of these routes calls Meta
*before* it persists anything:
- broadcast: makes no database write at all, so there was no policy
involved on any path
- send / react: the Meta call precedes the insert, so the outbound
message or reaction reached the customer and only the local mirror
was refused
- templates/submit, templates/sync: push to Meta before upserting the
local catalog
Gate each handler at the role its data class already implies, matching
lib/auth/roles and the migration 017 policies:
- send, react, broadcast -> 'agent' (canSendMessages)
- templates/submit, sync -> 'admin' (canEditSettings, and the
message_templates_insert/update
policies)
Also switches these handlers to toErrorResponse so an authorization
failure returns 401/403 instead of being folded into a generic 500. The
two template routes keep their existing message-surfacing 500 for
non-auth errors, so a Meta failure still reports its own reason.
Adds role-enforcement coverage to the send route's test: a viewer is
refused with 403 and sendTemplateMessage is never called, while an agent
passes through.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses GHSA-8fv4-vgcc-p8vm.
The five write handlers under
/api/whatsappresolved the caller'saccount_idfrom their profile but never checked their role, so accountmembership alone was enough to reach them. Every other write surface in the
app (
account/,ai/,automations/,flows/,quick-replies/) alreadygoes through
requireRole(); this family was missed when GHSA-34q7-fv77-625jadded those guards.
Each handler now calls
requireRole()before any outbound call, at the roleits data class already implied in
src/lib/auth/roles.tsand the migration017 policies:
send,react,broadcastagent(canSendMessages)templates/submit,templates/syncadmin(canEditSettings)Authorization failures now return 401/403 via
toErrorResponserather thanbeing folded into a generic 500. The two template routes keep their existing
message-surfacing 500 for non-auth errors, so a Meta failure still reports
its own reason.
Tests
Adds role-enforcement coverage to the send route: a viewer is refused with
403 and
sendTemplateMessageis never called, while an agent passes through.Verified failing against the pre-fix code.
Full local run against this branch:
eslint39 warnings / 0 errors(unchanged from
main),tsc --noEmitclean, 654 tests pass,next buildexits 0.
Note
Open PR #403 proposes a
canManageTemplatespermission that would letagents manage templates. If that lands, the
admingate on the two templateroutes here should be relaxed to match. (#403 also numbers its migration
037, which collides with037_webhook_broadcast_reliability.sql.)🤖 Generated with Claude Code