Harvey / The auditMethodology

What a Harvey audit actually does.

Ten modules, equal weight — a senior quality leader's read across your whole codebase, not a single-issue scan. Here is exactly what runs, how we prove it, and how we tell you what we didn't check.

Ten modules · equal weight

The ten modules.

No module is the headline. The deliverable is the true state of your codebase across all ten — one readiness verdict. Each module runs at the tier its data allows; nothing runs at a shallower depth than your engagement supports.

M1

Multi-tenant security & access control

Who can read and write what. We review auth boundaries, Row-Level Security policy semantics (not just on/off), service-role key exposure, IDOR, over-fetching API routes, and cross-tenant isolation — the class of flaw that lets one user reach another's data.

Runs at: Free (mechanical) → Connected (live RLS) → Full (semantic review)
M2

Live pen-test

We stand up a copy of your stack locally, seed two tenants and two users, and actually try to cross the boundary — reading tenant B's rows as tenant A, probing auth attacks, session lifecycle, endpoints, storage objects, invitations and share links, data left behind after a delete, and service seams. A finding here isn't a warning; it's the row we should never have been able to read. Every run also records what it stood up, and every access path it did not exercise, with the reason.

Runs at: Full audit only (stands up your stack)
M3

Hotspot analysis

Where complexity and change collide. We rank files by churn × complexity to find the few files that concentrate most of your bug risk — the ones that keep breaking every time you touch them.

Runs at: Free (source)
M4

Duplication

Copy-pasted logic that drifts out of sync, so a fix in one place silently misses the others. We measure duplicated blocks and near-miss clones that diverged after being copied.

Runs at: Free (source)
M5

Dead code / slop

What's shipped but never runs — unused exports, unreachable files, dependencies you no longer need. The dead weight an AI assistant tends to leave behind.

Runs at: Free (source)
M6

Maintainability / simplification

Hand-rolled code that has a safer, standard replacement. We flag reinvented auth, ad-hoc parsers, and fragile custom logic, then — on the paid tiers — name the specific library or pattern to replace it with.

Runs at: Free (indicators) → Full (named replacement)
M7

Performance

N+1 queries, missing indexes, render-time fetch waterfalls, RLS policies that re-evaluate per row, and Core Web Vitals. What will get slow — and what will fall over — when traffic scales.

Runs at: Free (code) → Connected (DB advisors) → local Lighthouse
M8

Test quality

Which of your tests can't actually catch a bug. We run mutation testing — deliberately break your code and report which tests still pass anyway. A green suite that can't fail is worse than no suite, because it's trusted.

Runs at: Free (test-intent) → Full (mutation run)
M9

Server→client boundaries

Server→client data leaks, environment variables reachable from the browser, and server actions missing auth or input validation — the ways a boundary quietly becomes public. Analysed on Next.js, Remix, React Router 7 and TanStack Start; a framework we don't yet model is named in the ledger as not assessed, never run on a false premise.

Runs at: Free (source)
M10

Data classification

Every column holding PII, PHI, or PCI data, and whether it's protected. Mapped from your schema for free, and verified against your live database on the connected tier.

Runs at: Free (schema) → Connected (live)
The trust feature

The coverage ledger: we show you what we didn't check.

An unstated limitation reads as a clean bill of health. Most reports go quiet about what they skipped. Every Harvey report carries a coverage ledger instead — each module, its status, and the reason if it couldn't run. A module that couldn't run is listed as "Not run" with its reason, never silently dropped.

M1 · Access control & data securityRLS + auth reviewedRan
M8 · Test qualitymutation run completeRan
M7 · Performance (DB advisors)needs a connected databaseNot run
M2 · Live pen-testFull-audit tier — not in this engagementNot run

A real ledger from a real report. The two "Not run" rows tell you precisely what a deeper tier would add.

Prove it, don't flag it

The live pen-test, explained.

Static analysis can tell you a policy looks like it lets the wrong user in. It can't tell you whether it actually does — that depends on how your auth, your policies, and your queries interact at runtime. So on the Full audit, Harvey stops guessing and tests it.

  1. We stand up a copy of your stack. Harvey provisions its own local Supabase — or plain Postgres for a Prisma app — applies your migrations, and boots your app. No contact with your production environment.
  2. We seed two tenants and two users. Two separate accounts with separate data, exactly like two real customers.
  3. We try to cross the boundary. Signed in as user A, Harvey runs the cross-tenant matrix against your live PostgREST API and app routes, plus auth-attack and service-seam probes — attempting to read and write data that belongs to user B.
  4. The finding is the evidence. If the boundary holds, we record that it holds. If it doesn't, the report shows the actual row we retrieved that we never should have been able to see. Proof, not a warning.
  5. And we record what we stood up. A local copy built from your code and migrations is not your production configuration, so every run states what was reconstructed, from which commit, and which access paths it did not exercise. You get the boundary of the evidence along with the evidence.

This is the work that a source-only "vibe-code audit" structurally cannot do, and it's the only tier that carries pen-test language. It's reserved for the Full audit because standing up and attacking a running copy of your stack is the expensive, high-value work.

Start free

See the real state of your codebase.

Source-only, no credentials, yours to keep.