Scan a repository
Back to the home page

This is an example report on a demo app, showing what an AI Review produces. Nothing here came from your code.

github.com/example/demo-shop

Scanned 72 hours ago · took 2m 48s

Don't ship yet

3 things here can be used against you as the code stands today.

Paste it into the assistant you built this with. It has your code open — the prompt carries what to change and how to check it worked.

Fix before launch 3

  • CriticalAnyone signed in can read every user's datasupabase/migrations/0002_profiles.sql:12Code scan

    The access rule on the profiles table allows any logged-in account to select any row. Someone signs up normally, opens the browser console, and reads every email address, phone number and Stripe customer id the app holds. No exploit needed — this is the database doing what it was told.

    AI Review: Confirmed — Confirmed against the migration that created the policy: `USING (true)` matches every row, so any authenticated user can select any other user's profile.

    Fix prompt

    In supabase/migrations/0002_profiles.sql, drop the permissive select policy on `profiles` and create one restricted to the owner (auth.uid() = user_id). Constraint: Leave the insert and update policies alone; do not disable RLS on the table to make anything pass. Verify: Sign in as a second user and assert they cannot select the first user's row.

    Found by Code scan · rls-permissive-select

  • HighThe admin check only runs in the browserapp/api/admin/users/route.ts:8Code scan

    The dashboard hides admin buttons from normal users, but the API route behind them never checks who is calling. Anyone can call that endpoint directly with curl and do everything an admin can. Hiding a button is a UI decision, not a permission.

    AI Review: Confirmed — No server-side authorization check exists anywhere under app/api/admin — the only admin check in the codebase is the conditional render in components/AdminPanel.tsx.

    Fix prompt

    Add a server-side check at the top of every handler under app/api/admin that loads the session and returns 403 unless the user has the admin role. Constraint: Extract the check into one shared helper so a new route under app/api/admin cannot forget it. Verify: Add a test asserting a non-admin session gets 403 from every route under app/api/admin.

    Found by Code scan · authz-client-only

  • HighAnyone can fake a successful paymentapp/api/webhooks/stripe/route.ts:15Code scan

    The Stripe webhook accepts any POST without verifying it came from Stripe. Someone can send a fake "payment succeeded" event and get a paid plan for free. This is the most common way small products lose money without noticing.

    AI Review: Confirmed — `stripe.webhooks.constructEvent` is never called in this handler; the request body is trusted outright, so a forged "payment succeeded" event is indistinguishable from a real one.

    Fix prompt

    Verify the Stripe signature with stripe.webhooks.constructEvent using the raw request body and STRIPE_WEBHOOK_SECRET, returning 400 when verification fails. Constraint: Read the raw body via `await req.text()`, not `req.json()` — the Next.js App Router detail that makes the signature match at all. Verify: Add a test asserting an unsigned request is rejected with 400.

    Found by Code scan · webhook-unverified

AI Review

Reviewed all 3 findings from this scan. All three are real and independent — none share a root cause, so fixing one will not fix another.

Reviewed with claude-opus-5. Details on each finding below.

Add Repository

Scans run against this branch. If your work happens on develop, say so — scanning main would report on code nobody is writing any more, and read as an all-clear.

Every Security Check reads your code for logic flaws and insecure patterns, and checks your dependencies for known vulnerabilities and exposed secrets. Your repository is never executed, and secrets are masked before anything leaves our servers.

CodexMotiveShield — an audit for the app you did not entirely write.

© 2026 CodexMotive. Scanning reads your files; it never runs them.

Checking your session…