Summary
The GET and PATCH handlers for /api/feedback/[id] were shipping without any authentication or tenant-isolation checks. Both handlers used createAdminClient() (bypasses RLS entirely), and the middleware explicitly skips all /api/ routes, leaving the endpoint fully open to any HTTP caller with a session UUID.
Detected by: Automated security review (Claude Code /security-review) on 2026-04-10.
Vulnerability Detail
| Property |
Value |
| Endpoint |
GET /api/feedback/:id, PATCH /api/feedback/:id |
| Auth before fix |
None |
| Client used before fix |
createAdminClient() — RLS bypassed |
| Middleware protection |
None — middleware passes all /api/ routes through |
GET exploit: Any caller with a known session UUID could retrieve all feedback items for that session, including outer_html (raw HTML of internal admin pages), css_classes, parent_chain, comment, and page paths — internal UI structure of the tenant's admin dashboard.
PATCH exploit: Any caller with a known session UUID could send {"status":"completed"} to irreversibly close feedback sessions belonging to any tenant.
Fix Applied
Both handlers now go through resolveApiContext(request) — the same auth middleware used by all other /api/ routes (e.g. /api/content-catalogs). This supports:
- Mode A: App credential JWT (for integrations)
- Mode B: Supabase user Bearer token +
X-Tenant-Id header
After auth, both handlers explicitly verify session.tenant_id === auth.ctx.tenantId before returning data or mutating state, providing full tenant isolation even when called with a valid token from a different tenant.
The admin client is retained (required for admin-level reads), but it is now backed by application-layer tenant checks rather than running unauthenticated.
Files Changed
src/app/api/feedback/[id]/route.ts — added resolveApiContext auth + tenant check to GET and PATCH
Summary
The
GETandPATCHhandlers for/api/feedback/[id]were shipping without any authentication or tenant-isolation checks. Both handlers usedcreateAdminClient()(bypasses RLS entirely), and the middleware explicitly skips all/api/routes, leaving the endpoint fully open to any HTTP caller with a session UUID.Detected by: Automated security review (Claude Code
/security-review) on 2026-04-10.Vulnerability Detail
GET /api/feedback/:id,PATCH /api/feedback/:idcreateAdminClient()— RLS bypassed/api/routes throughGET exploit: Any caller with a known session UUID could retrieve all feedback items for that session, including
outer_html(raw HTML of internal admin pages),css_classes,parent_chain,comment, andpagepaths — internal UI structure of the tenant's admin dashboard.PATCH exploit: Any caller with a known session UUID could send
{"status":"completed"}to irreversibly close feedback sessions belonging to any tenant.Fix Applied
Both handlers now go through
resolveApiContext(request)— the same auth middleware used by all other/api/routes (e.g./api/content-catalogs). This supports:X-Tenant-IdheaderAfter auth, both handlers explicitly verify
session.tenant_id === auth.ctx.tenantIdbefore returning data or mutating state, providing full tenant isolation even when called with a valid token from a different tenant.The admin client is retained (required for admin-level reads), but it is now backed by application-layer tenant checks rather than running unauthenticated.
Files Changed
src/app/api/feedback/[id]/route.ts— addedresolveApiContextauth + tenant check to GET and PATCH