Harvey / Sample reportWhat you get

A Harvey report, front to back.

Every finding in plain English, ranked by blast radius, each with where it is, why it matters, and how to fix it — plus the coverage ledger that tells you what we didn't check. This is the shape of what lands in your inbox.

Sample — synthetic data for a fictional app ("Larkspur"). Not a real client's codebase.
Readiness report
Larkspur (sample)
Multi-tenant Supabase / Next.js booking app · Full audit · Small · ~8k lines
Verdict
Not ready to scale
One cross-tenant read was proven live and one N+1 will not survive traffic. The rest are hardening, test-quality, and maintainability wins — all with named fixes.
1
Critical
1
High
3
Medium
4
Low / Perf
1
Clean
Findings · ranked by blast radius

Every finding, with the fix.

Ordered by what matters for this app, not by module. Critical and High first — the things to fix before scaling — then the hardening, test-quality, and maintainability wins.

CriticalF-01M2 · Live pen-test

Cross-tenant read proven: user A can read user B's bookings

public.bookings (RLS policy "read own bookings")

Evidence
On the stood-up stack, signed in as tenant A, a request to /rest/v1/bookings returned tenant B's rows. The policy uses USING (auth.role() = 'authenticated') — it checks that you're logged in, not that the row is yours.
Impact
Any signed-in customer can read every other customer's bookings, including names, dates, and contact details. This is a direct data-exposure incident, not a theoretical one.
Fix
Rewrite the policy to scope by owner: USING (user_id = auth.uid()). Re-run the cross-tenant matrix to confirm the boundary now holds.
HighF-02M7 · Performance

N+1 query on the dashboard loads one query per booking

app/dashboard/page.tsx

Evidence
The dashboard fetches the booking list, then issues a separate customer lookup inside the render loop — N+1 queries that scale linearly with row count.
Impact
At 20 bookings the page is fine; at 2,000 it issues 2,000 queries per load and times out. This is what falls over on launch day.
Fix
Replace the per-row lookup with a single joined query (select with an embedded resource), or batch the customer IDs into one in() query.
MediumF-03M1 · Access control

service_role key reachable from a client-imported module

lib/supabase/admin.ts

Evidence
The admin client is instantiated with the service_role key in a module that is transitively imported by a client component. It is not currently called from the browser, but nothing prevents it.
Impact
The service_role key bypasses RLS entirely. A future accidental client import would bundle a master key to the database into the browser.
Fix
Move the admin client behind a server-only boundary and add import 'server-only' so an accidental client import fails the build.
MediumF-04M8 · Test quality

The refund guard has a test that can't fail

lib/billing/refund.ts

Evidence
Mutation testing: deleting the amount <= originalCharge check left every test green. No test asserts that an over-refund is rejected on money-critical logic.
Impact
A regression that allows refunding more than was charged would ship undetected — the suite would still pass.
Fix
Add one test asserting a refund greater than the original charge is rejected.
MediumF-05M10 · Data classification

PII sitting in three columns with no access policy

customers.phone, customers.address, customers.date_of_birth

Evidence
Schema classification flagged three PII columns on a table whose RLS is enabled but whose SELECT grant is broader than the policy intends.
Impact
Personal contact data is more broadly readable than the app appears to intend — a privacy and compliance exposure.
Fix
Tighten the SELECT grant to match the intended policy, and confirm no client path reads these columns unnecessarily.
LowF-06M9 · Server→client boundaries

A Server Action mutates without checking the caller

app/bookings/actions.ts (cancelBooking)

Evidence
The Server Action accepts a bookingId and cancels it with no ownership check — it trusts that the UI only offers the button on the user's own bookings.
Impact
Anyone who can call the action with an arbitrary bookingId can cancel another tenant's booking (IDOR via a Server Action).
Fix
Verify the booking belongs to auth.uid() inside the action before mutating; never rely on the UI to enforce authorization.
LowF-07M4 · Duplication

Date-formatting logic copy-pasted across six components

components/** (6 clones)

Evidence
jscpd: the same timezone-handling block appears in six components, already diverged in two of them.
Impact
A fix to one copy silently misses the others — the two that diverged already render times differently.
Fix
Extract one formatBookingTime helper and replace the six copies.
LowF-08M6 · Maintainability

Hand-rolled session parsing where a library exists

lib/auth/session.ts

Evidence
Custom cookie parsing and JWT decoding reimplement what the Supabase auth-helpers already provide, with an edge case that mishandles an expired token.
Impact
Fragile reinvented auth code — the exact category that quietly breaks and is hard to reason about.
Fix
Replace with the maintained Supabase auth-helpers session handling.
InfoF-09M3 · Hotspots

app/api/webhook/route.ts is the #1 hotspot

app/api/webhook/route.ts

Evidence
vitals: high complexity, 28 changes in 90 days, co-changes with 14 files.
Impact
Central, churny, and complex — a future-bug magnet with wide blast radius.
Fix
Decompose into handlers. High value but slow and risky — schedule as a planned refactor, not a quick win.
InfoF-10M5 · Dead code

No dead code worth pruning

repo-wide

Evidence
knip found 3 unused exports, all framework entry points — nothing to remove.
Impact
Clean. Noted for transparency; not every module produces a finding.
Fix
No action.
No silent gaps

The coverage ledger.

Ten modules, each with its status and — where it couldn't fully run — the reason. On this sample, M10 ran on the schema but the live PII-grant check is still pending the client's database sign-off, so it's marked partial rather than dropped.

M1 · Access control & data securityRLS + auth reviewed, live-verifiedRan
M2 · Live pen-teststack stood up, cross-tenant matrix runRan
M3 · Hotspot analysischurn × complexity computedRan
M4 · Duplicationjscpd + near-miss passRan
M5 · Dead codeknip over installed depsRan
M6 · Maintainabilityindicators + reviewed verdictRan
M7 · Performancecode tier + DB advisors + LighthouseRan
M8 · Test qualitymutation run completeRan
M9 · Server→client boundariesstatic AST passRan
M10 · Data classificationschema classification; live PII grants pending client sign-offPartial
Get yours

Want this for your codebase?

The free scan returns a real ten-module report on your source — same shape, your findings. Point us at your repo and we'll send it within one business day.

Source-only, no credentials, yours to keep.