NEWAI-Powered Code Review

Find bugs beforeyour users do.

Three AI agents debate your code. One verified fix. Automatic pull request. Developers stay in control — always.

3 agents · consensus reached
Critical bug found
.env.local · Hardcoded secret
PR created
faultmark/fix-sql-injection → main
CRITICAL
Hardcoded API Secret
.env.local
HIGH
SQL Injection
app/api/search/route.ts
app.faultmark.com/dashboard/repos/acme-api
Repos
SCAN RESULTS
acme-api
acme-corp/acme-api
Branch: mainScan Complete0 bugs found
BUGS FOUND0 confirmed · 0 disputed

How a finding earns its confidence score.

01
Code Input
Entrypoint
  • ·GitHub diff or full repo
  • ·Files prioritized by impact
  • ·Token budget allocated
02
Pre-Analysis
Deterministic profiling
  • ·Scan profile built
  • ·Impact scope computed
  • ·Scan depth selected
  • ·Scope expands on high risk
03PARALLEL
Parallel Review
Three isolated agents
Agent 1
Async flows · Race conditions · Concurrency
Agent 2
Type safety · Null paths · Boundaries
Agent 3
Edge cases · Error paths · Data flow
04
Cross-Examination
Divergence scoring
  • ·Findings compared
  • ·Confidence delta computed
  • ·Disputed findings isolated
  • ·2/3 consensus required
05
AI Verification
Lightweight gate
  • ·False positives suppressed
  • ·Plausibility checked
  • ·Evidence threshold enforced
  • ·Weak findings dropped
06PRO
Multi-Model Debate
3 independent AI models
  • ·Adversarial re-examination
  • ·Blind spots cross-checked
  • ·Root-cause agreement required
  • ·Disputes surface as DISPUTED
07
Verified Report
Delivered to developer
  • ·HIGH / MEDIUM / LOW / DISPUTED
  • ·Fix proposal per finding
  • ·Auto PR for HIGH confidence
  • ·Confidence score per model

Multi-model debate available on Pro. Free tier: single-model with AI verification gate.

Three models walk into your codebase.

They disagree constantly. That's the point. Only findings all three agree on make it to your report.

Agent 1Agent 2Agent 3DebateEngineVerifiedFix

Isolated analysis

Each agent examines your code separately. Agent 1 traces async flows, Agent 2 checks type safety, Agent 3 covers edge cases.

Scored divergence

When models conflict, the engine scores the gap. Only consensus findings make it to your report.

No false consensus

Every bug survived three independent critics. Fix proposals appear only when all three models agree on root cause.

Everything a senior engineer
would catch. Automated.

Three models, one verdict

Every potential bug runs through three independent AI agents. Only findings that survive cross-examination reach your report.

Agent 1
94%
Agent 2
91%
Agent 3
88%

Real errors, not synthetic noise

BUG FOUND · auth.ts line 7
Unhandled null reference: user.profile.prefs will throw on unauthenticated requests.
Confidence: HIGH · 3/3 models

What breaks at 3am

null / undefined inputfail
empty string edge casepass
max length + 1fail
concurrent writefail
unicode boundarypass

Concrete fixes, not hints

Faultmark never auto-deploys. You review the fix, approve the PR, ship when ready.

- return user.profile.prefs
+ const prefs = user?.profile?.prefs
+ return prefs ?? null

High / Medium / Low / Disputed

HIGHauth.ts:7null ref on user.profile
MEDIUMutils/date.ts:11Date boundary overflow
LOWconfig.ts:3Unused import side-effect
DISPUTEDapi/route.ts:23Potential race condition

Disputed bugs surface in a separate review queue.

One click to pull request

fix: handle null user.profile in auth
faultmark/fix-null-ref-auth-7 → main

Now watching pushes and pull requests

Faultmark audits the work that happens after the first scan.

Manual scans build deep repo context. Push and pull audits use that context automatically, so new changes are reviewed while developers are already working in GitHub.

Every push gets a lightweight security pass.

Faultmark listens for GitHub push events, reviews only what changed, pulls in repo memory, then sends a concise summary to your inbox. When there’s a real finding, it opens an audit PR automatically.

github.com / acme-corp / api / pull / 27
Pull request #27
security: harden API input handling and access control
Open
F
faultmark-app reviewed this pull request
just now

Faultmark Automated Security Audit

3 issues found. Review each finding below and apply fixes before merging.
This PR was automatically opened by Faultmark in response to a direct push. No code has been modified in this branch. This is a read-only audit report.

Summary
Commit scanneda4d7e2c
Branchmain
Overall scan confidence████████░░ 82% (High)
Issues found3
Severity Breakdown
SeverityCount
Critical2
High1
Total3

Findings (3)
Finding 1: Unsanitized query parameter passed directly to database lookup
Severity[CRITICAL]
TypeInjection Attack
Filelib/db/search.ts · L34–L41
Per-finding confidence█████████░ 91%
Validation statusValidated — no contradicting evidence found
What's Wrong

`searchTerm` from `req.query` is interpolated directly into the SQL string without parameterization. An attacker can craft a value like `' OR 1=1 --` to bypass filters and read arbitrary rows.

Problematic Code
const rows = await db.query(
  `SELECT * FROM users WHERE name = '${searchTerm}'`
)
Suggested Fix
const rows = await db.query(
  'SELECT * FROM users WHERE name = $1',
  [searchTerm]
)
Why this fix works: Parameterized queries separate SQL structure from data, making injection impossible regardless of input content.
Finding 2: Admin delete endpoint missing authorization check
Severity[CRITICAL]
TypeAuth Bypass
Fileapp/api/admin/users/[id]/route.ts · L12–L28
Per-finding confidence█████████░ 88%
Validation statusValidated — no contradicting evidence found
What's Wrong

The `DELETE` handler calls `db.deleteUser(id)` before verifying the session has admin role. Any authenticated user can delete any account by calling this endpoint directly.

Problematic Code
export async function DELETE(req, { params }) {
  const session = await getSession(req)
  if (!session) return unauthorized()
  await db.deleteUser(params.id)
  return ok()
}
Suggested Fix
export async function DELETE(req, { params }) {
  const session = await getSession(req)
  if (!session || session.user.role !== 'admin')
    return unauthorized()
  await db.deleteUser(params.id)
  return ok()
}
Why this fix works: Role check must happen before any destructive operation. Checking authentication alone is insufficient.
Finding 3: Payment amount truncated on currency conversion — potential overcharge
Severity[HIGH]
TypeLogic Error
Filelib/billing/convert.ts · L88–L96
Per-finding confidence████████░░ 76%
Validation statusPartially validated — some conflicting signals present
What's Wrong

`Math.round()` is applied before multiplying by the exchange rate, discarding fractional cents. For large transactions this can produce totals that are off by up to ±5 cents, affecting reconciliation and potentially overcharging customers.

Problematic Code
const cents = Math.round(amount) * exchangeRate
Suggested Fix
const cents = Math.round(amount * exchangeRate)
Why this fix works: Rounding should occur after all arithmetic to minimise precision loss. Apply it as the last operation before storing or charging.
View full interactive report on faultmark.com · This PR is read-only and safe to close if no action is required.

PRs get reviewed the moment they move.

Open or update a pull request and Faultmark reads the diff, debates uncertain findings, and posts one clean GitHub review comment with severity, confidence, and evidence your reviewer needs to act.

github.com / acme-corp / api / pull / 42
Pull request #42
feat: add auth hardening and user profile endpoint
Open
F
faultmark-app left a review on this pull request
just now

Faultmark PR Security Review

3 issues confirmed after debate review. 1 finding dropped — contradicted by existing middleware.
Review findings below before merging. Apply fixes or accept proposals via the Faultmark dashboard.

Summary
PR#42 — add auth hardening + user profile endpoint
Head commitc9f3e81
Files reviewed9 changed files
Scan confidence█████████░ 85% (High)
Issues found3
Dropped after debate1
Severity Breakdown
SeverityCount
High2
Medium1
Total3

Findings (3)
Finding 1: No rate limiting on password reset endpoint
Severity[HIGH]
TypeImproper Validation
Fileapp/api/auth/reset-password/route.ts · L18–L34
Per-finding confidence█████████░ 85%
Validation statusValidated — no contradicting evidence found
What's Wrong

The new `/reset-password` endpoint introduced in this PR accepts unlimited requests per IP address. An attacker can brute-force reset tokens or trigger mass emails at zero cost.

Problematic Code
export async function POST(req: Request) {
  const { email } = await req.json()
  await sendResetEmail(email)
  return NextResponse.json({ ok: true })
}
Suggested Fix
export async function POST(req: Request) {
  const ip = req.headers.get('x-forwarded-for') ?? 'unknown'
  await ratelimit.check(ip, { limit: 5, window: '15m' })
  const { email } = await req.json()
  await sendResetEmail(email)
  return NextResponse.json({ ok: true })
}
Why this fix works: Rate-limit by IP before any processing. A window of 5 requests per 15 minutes is a reasonable default for password reset flows.
Finding 2: User object returned with password hash in API response
Severity[HIGH]
TypeData Exposure
Fileapp/api/users/[id]/route.ts · L41–L48
Per-finding confidence█████████░ 92%
Validation statusValidated — no contradicting evidence found
What's Wrong

The updated `GET /users/:id` handler returns the full Drizzle row including `passwordHash`. Any client that calls this endpoint receives the hash, making offline cracking trivial.

Problematic Code
const [user] = await db
  .select()
  .from(users)
  .where(eq(users.id, params.id))

return NextResponse.json(user)
Suggested Fix
const [user] = await db
  .select({
    id: users.id,
    name: users.name,
    email: users.email,
    plan: users.plan,
  })
  .from(users)
  .where(eq(users.id, params.id))

return NextResponse.json(user)
Why this fix works: Always use explicit column selection when returning user data. Never rely on the caller to strip sensitive fields after the fact.
Finding 3: Async file write not awaited — race condition on concurrent uploads
Severity[MEDIUM]
TypeRace Condition
Filelib/storage/upload.ts · L62–L71
Per-finding confidence███████░░░ 73%
Validation statusPartially validated — some conflicting signals present
What's Wrong

`fs.writeFile` is called without `await`. On concurrent uploads for the same key the file can be partially written by one request while another reads it, producing corrupted data.

Problematic Code
fs.writeFile(filePath, buffer, (err) => {
  if (err) logger.error('write failed', err)
})
return { key: filePath }
Suggested Fix
await fs.promises.writeFile(filePath, buffer)
return { key: filePath }
Why this fix works: Use the promise-based API and await the write before returning. This ensures callers see a consistent file state and errors surface as exceptions rather than silent log entries.
View full interactive report on faultmark.com · Powered by Faultmark

Every push reviewed in full codebase context.

01
Push Event
GitHub webhook
  • ·Branch filter applied
  • ·Supersession check
  • ·Duplicates deduplicated
02
Diff Extraction
Smart Delta engine
  • ·Semantic changes only
  • ·Changed units isolated
  • ·Regressions detected
  • ·Full rebuild on large refactor
03
Pre-Analysis
Impact scoping
  • ·Scan profile built
  • ·Impact scope computed
  • ·Depth: incremental / deeper / full
  • ·Scope expanded on high risk
04PARALLEL
Memory Retrieval
Two sources in parallel
Structured Memory
  • Persistent codebase index
  • API surfaces + data flow
  • Architecture snapshots
  • Updated each scan
Semantic Memory
  • Vector embedding index
  • Top-K similarity search
  • Similarity threshold enforced
  • Finds related patterns
05
Hybrid Context
Context assembly
  • ·Diff + memory merged
  • ·Token budget enforced
  • ·Ordered by risk level
  • ·High-risk files prioritized
06
Debate System
See review pipeline
  • ·3 agents run in parallel
  • ·Cross-examination pass
  • ·AI verification gate
  • ·Multi-model consensus on Pro
07
Delivery
Developer notification
  • ·Audit PR on GitHub
  • ·Summary email sent
  • ·Routed by severity
  • ·Silent when no findings

Push audits use Smart Delta to detect only semantically significant changes. Full rebuild queued automatically on large refactors.

TypeScript·JavaScript·Python·Go·Rust·Java·C#·C++·Swift·Kotlin·Ruby·PHP·Scala·Elixir·Dart·Lua·Bash·PowerShell·R·Julia·Zig·Nim·Groovy·Perl·React·Vue·Angular·Svelte·Next.js·Nuxt·Remix·Astro·SvelteKit·Qwik·SolidJS·Preact·Alpine.js·HTMX·Lit·Vite·Webpack·esbuild·Rollup·Tailwind CSS·Node.js·Express·NestJS·Fastify·Hono·Django·Flask·FastAPI·Rails·Spring Boot·Laravel·Phoenix·Gin·Echo·Fiber·Axum·Actix·gRPC·GraphQL·tRPC·PostgreSQL·MySQL·MongoDB·Redis·SQLite·Cassandra·Elasticsearch·DynamoDB·Supabase·PlanetScale·CockroachDB·Drizzle ORM·Prisma·TypeORM·SQLAlchemy·Hibernate·GORM·Docker·Kubernetes·Terraform·Pulumi·AWS·GCP·Azure·GitHub Actions·CircleCI·GitLab CI·Vercel·Netlify·Railway·Fly.io·Cloudflare Workers·AWS Lambda·Kafka·RabbitMQ·NATS·SQS·Pub/Sub·TypeScript·JavaScript·Python·Go·Rust·Java·C#·C++·Swift·Kotlin·Ruby·PHP·Scala·Elixir·Dart·Lua·Bash·PowerShell·R·Julia·Zig·Nim·Groovy·Perl·React·Vue·Angular·Svelte·Next.js·Nuxt·Remix·Astro·SvelteKit·Qwik·SolidJS·Preact·Alpine.js·HTMX·Lit·Vite·Webpack·esbuild·Rollup·Tailwind CSS·Node.js·Express·NestJS·Fastify·Hono·Django·Flask·FastAPI·Rails·Spring Boot·Laravel·Phoenix·Gin·Echo·Fiber·Axum·Actix·gRPC·GraphQL·tRPC·PostgreSQL·MySQL·MongoDB·Redis·SQLite·Cassandra·Elasticsearch·DynamoDB·Supabase·PlanetScale·CockroachDB·Drizzle ORM·Prisma·TypeORM·SQLAlchemy·Hibernate·GORM·Docker·Kubernetes·Terraform·Pulumi·AWS·GCP·Azure·GitHub Actions·CircleCI·GitLab CI·Vercel·Netlify·Railway·Fly.io·Cloudflare Workers·AWS Lambda·Kafka·RabbitMQ·NATS·SQS·Pub/Sub·TypeScript·JavaScript·Python·Go·Rust·Java·C#·C++·Swift·Kotlin·Ruby·PHP·Scala·Elixir·Dart·Lua·Bash·PowerShell·R·Julia·Zig·Nim·Groovy·Perl·React·Vue·Angular·Svelte·Next.js·Nuxt·Remix·Astro·SvelteKit·Qwik·SolidJS·Preact·Alpine.js·HTMX·Lit·Vite·Webpack·esbuild·Rollup·Tailwind CSS·Node.js·Express·NestJS·Fastify·Hono·Django·Flask·FastAPI·Rails·Spring Boot·Laravel·Phoenix·Gin·Echo·Fiber·Axum·Actix·gRPC·GraphQL·tRPC·PostgreSQL·MySQL·MongoDB·Redis·SQLite·Cassandra·Elasticsearch·DynamoDB·Supabase·PlanetScale·CockroachDB·Drizzle ORM·Prisma·TypeORM·SQLAlchemy·Hibernate·GORM·Docker·Kubernetes·Terraform·Pulumi·AWS·GCP·Azure·GitHub Actions·CircleCI·GitLab CI·Vercel·Netlify·Railway·Fly.io·Cloudflare Workers·AWS Lambda·Kafka·RabbitMQ·NATS·SQS·Pub/Sub·

3 scans free. Unlimited on Pro.

For solo developers

Free

$0
  • ·3 scans / month
  • ·AI static analysis
  • ·Fix proposals included
Start free

For teams that ship

Pro

$29.99/ month
  • ·Up to unlimited scans
  • ·Multi-model AI debate (3 models)
  • ·Higher-confidence reports
  • ·Priority scan queue
  • ·Fix proposals included
Get started

Your next deploy,
bulletproofed.

Log in / Sign up