LQ-01 · High
Staff can read any employee's expense by changing its ID
Evidence
Original synthetic evidence and records.
GET /rest/v1/expenses?id=eq.1042 as staff@test.example → 200, owner_id ≠ caller. Policy expenses_select uses auth.role() = 'authenticated'.
Fix plan
In Supabase, update the SELECT policy on public.expenses so Staff can only read rows where owner_id = auth.uid(), and Managers can read rows where team_id matches their team via a security-definer has_role check. Do not change other tables.
Retest outcome
Fixed — Retest 14 Oct 2026: request returned 0 rows for Staff; Manager access intact.
LQ-02 · High
Staff can approve expenses through the API
Evidence
Original synthetic evidence and records.
POST /functions/v1/approve-expense {id:1051} as staff@test.example → 200, status changed to approved.
Fix plan
In the approve-expense function, verify the caller has the manager role using the user_roles table before updating. Return 403 otherwise. Hiding the button is not enough.
Retest outcome
Still present — Retest 14 Oct 2026: role check added in UI layer only; API still accepted Staff approval.
LQ-03 · Medium
Receipt share links work without signing in and never expire
Evidence
Original synthetic evidence and records.
Bucket 'receipts' public = true. Object URL fetched without auth → 200.
Fix plan
Make the receipts storage bucket private and serve receipts via signed URLs with a 10-minute expiry, generated only for users allowed to view the related expense.
Retest outcome
Awaiting retest
LQ-04 · Low
Team export result could not be confirmed for Staff
Evidence
Original synthetic evidence and records.
Export job exceeded 120s runner budget for both accounts. No response body captured.
Fix plan
Investigate why the monthly export job exceeds two minutes in staging with synthetic data. Confirm the export endpoint checks the manager role server-side.
Retest outcome
Awaiting retest
LQ-05 · High
Expense assistant lets Staff trigger the approve tool
Evidence
Original synthetic evidence and records.
Assistant tool approve_expense executed for a Staff session. Tool definition has no role requirement; server key used for the update.
Fix plan
In the assistant's approve_expense tool handler, run the update with the signed-in user's session (not the service key) and verify they have the manager role via has_role before executing. If not, return a refusal to the model. Apply the same rule to every tool that changes data.
Retest outcome
Awaiting retest