Technical deep-dive · for reviewers & evaluators

How Kagex works, end‑to‑end

Kagex is a GitHub-native, AI-powered security layer for Solidity. This page describes every subsystem and how it works internally — the multi-agent analysis engine, the scoring and regression machinery, the self-improving knowledge base, and the open reputation layer built on top.

Next.js 16 · React 19 · TSPostgreSQL · DrizzleBullMQ · RedisClaude (multi-agent)GitHub OAuth + App

00Engineering thesis

Why the system is shaped the way it is.

A manual audit certifies a single commit. Every commit after it ships unreviewed, because no team can afford an audit per pull request. Kagex closes that gap: it reviews every change with an AI pipeline whose output is deterministic in structure, stable across re-scans, and compounding in quality — then turns the result into a public, verifiable security score.

Structured, not scraped

Findings return through JSON-schema structured outputs — a successful response is guaranteed valid. No regex parsing, no silent drops.

Stable across re-scans

Content-addressed fingerprints keep an unchanged issue's identity, so triage and dismissals survive re-scans and regressions surface honestly.

Compounding

Every human-validated finding is distilled into an anonymized lesson that sharpens future scans across all protocols.

Open by default

The score, registry, and API are public goods — a shared reputation layer, not a walled dashboard.

01System architecture

Three planes: a Next.js app, an async analysis worker, and Claude.

The web app never runs a scan inline. A scan is a durable job: the app enqueues it and returns immediately; a dedicated worker consumes the queue, drives the AI pipeline, and writes results back — keeping request latency flat and scans crash-safe and retryable.

Developer / GitHub
Next.js app (RSC)
BullMQ · Redis
Scan worker
Claude (multi-agent)
PostgreSQL
LayerTechnologyRole
Web / APINext.js 16 (App Router, Server Components)UI, REST API, public score layer; server-side data-fetch
DataPostgreSQL + Drizzle ORMTyped schema, migrations, org-scoped queries
QueueBullMQ + RedisDurable jobs, retries, concurrency, stalled-job recovery
AIAnthropic ClaudeMulti-agent analysis, structured outputs & prompt caching
AuthGitHub OAuth + AppSign-in, repo access, installation tokens, webhooks

02Multi-agent scan pipeline

Two specialist agents per file, run concurrently, structurally constrained.

Each Solidity file is analyzed by two agents with distinct system prompts and knowledge bases:

  • Vulnerability Scanner — grounded in a curated knowledge base of 420+ vulnerability patterns from 800+ documented exploits. Reports every issue, honestly rated by severity and confidence.
  • Solidity Expert — reviews against best-practice coding standards: security patterns, gas efficiency, code quality.
Scan job
Vuln Scanner + KB
Solidity Expert
Structured output (JSON schema)
Orchestrator
Scoring + diff

Structured outputs — no parse gamble

Every call constrains the response to a JSON schema (output_config.format = json_schema). A success is guaranteed to match the findings schema — no fallback parsing, no dropped finding. A refusal or max_tokens stop reason throws — a truncated analysis fails loudly rather than reporting a partial "all clear".

Prompt caching

The large, static knowledge base carries a cache_control breakpoint, so every per-file call reuses the cached prefix. Learned lessons sit in a separate trailing cached block, keeping the stable KB prefix cache-hot even as lessons evolve.

Failure semantics

  • If every agent call fails, the scan fails outright (and is retried) — never reported as clean.
  • If some files failed, a would-be PASS is downgraded to PASS_WITH_WARNINGS so the gap is visible.
Adaptive reasoning
Agents run with adaptive extended thinking, so effort scales with the difficulty of the contract rather than a fixed budget.

03Per-scan-type model routing

Match model depth to the scan's job — pay for depth only where it matters.

A PR scan reviews a focused diff; a full audit reviews an entire codebase. Routing them to different models keeps PR feedback fast and cheap while reserving maximum reasoning for deep audits. The chosen model is persisted on each scan.

Scan typeModelWhy
PR scan · quick modeclaude-sonnet-5Small diff — snappy, affordable feedback loop
Full repo · upload · manual-review · cantinaclaude-opus-4-8Whole-codebase audit — maximum reasoning depth

Overridable per-tier via environment without code changes.

04Security scoring

A 0–100 score across seven categories, computed only from scan results.

The score is severity-weighted and status-aware. It is computed exclusively from findings — it cannot be purchased, boosted, or influenced. Dismissed and resolved issues stop counting; acknowledged issues count at half weight (the risk is real, the team has chosen to carry it).

Seven categories
Access Control · Reentrancy · Upgradeability · Oracle Safety · ERC Compliance · Math · Business Logic
Deduction per finding
= severity weight × status weight, applied to its category bucket
SeverityDeductionStatusWeight
critical30open · will-fix · in-progress1.0
high15acknowledged0.5
medium7resolved0
low2false-positive · invalid0

Model-produced free-text categories are normalized into the seven buckets deterministically (e.g. anything matching /reentran/ → Reentrancy). Each category yields a sub-score; the overall aggregates them — exactly the breakdown exposed on the public profile and scorecard badge.

05Fingerprints & suppression

Content-addressed identity so an issue is the same issue across scans.

Every finding gets a stable fingerprint. Cosmetic changes in the model's output (an added comment, re-quoted string, shifted line) must not create a "new" issue, and a genuine code change must:

fingerprint = sha256( file | category | swcId | normalize(snippet) )

normalize(s): strip block/line comments → collapse whitespace → lowercase

Suppression & status carry-forward

Prior statusBehavior on re-detection
false-positive · invalidSuppressed — a confirmed non-issue won't nag again (unless the code changes)
acknowledged · will-fix · in-progressCarried forward — triage state preserved, not reset to "open"
resolvedNot suppressed — if the same vulnerable code reappears, that is a regression and must surface
Algorithm-change resilient
Cross-scan comparison never trusts the stored fingerprint — it recomputes both sides from persisted fields with the current algorithm. Changing the fingerprint formula can therefore never cause phantom "everything is new / everything fixed" churn.

06Regression detection

Every scan is diffed against the right baseline.

A scan is compared against the previous completed scan of the same lineage; each finding is classified new, persisting, or fixed. The comparison scope is chosen so partial and full analyses never contaminate each other:

Scan is…Compared against…
Full repo scanthe latest full repo scan (never a PR scan)
PR scanprior scans of the same PR only
Upload (no repo)uploads across the same workspace

A "fixed" finding only counts if it held live risk in the baseline and is gone now — and only a full-repo scan updates the repo's public health score, since a PR scan sees only changed files.

07The learning loop — an “immune system”

Every validated finding makes every future scan — on any protocol — better.

When a team validates a finding — confirming a real vulnerability, or marking a false positive — Kagex distills it into a generalized, anonymized lesson and adds it to a shared knowledge base immediately. Confirmed patterns sharpen detection; false-positive patterns cut noise.

Team validates
confirmed pattern
over-flag pattern
anonymize
dedupe + confirmations
shared KB
every future scan

Anonymization (never leaks customer code)

A lesson is built from the finding's class-level fields (title, category, SWC id, description, impact, fix) — never raw code. A redaction pass strips protocol-identifying specifics before storage:

in:  transfer to 0xABCDEF123456 of "1000 tokens" costing 12345678 wei
out: transfer to <addr> of <value> costing <num> wei

Convergence & anti-poisoning

  • Deduped by (label, category, swcId, normalized title) with a confirmations counter — a pattern confirmed by many teams outranks a one-off, so the highest-signal lessons are injected first.
  • Mock/dev findings are skipped, so test data never pollutes the shared KB.
  • Lessons ride a dedicated cached prompt block — measurable, versioned, cheap to carry.

08The public score & registry

The score as shared infrastructure — a credit-rating layer for on-chain code.

Any protocol can opt a repository into a public profile. From there the score is readable by humans and machines — open and unfakeable because everything is served live from Kagex.

SurfaceEndpointServes
Public profile/p/{slug}Score, per-category breakdown, counts, freshness
Registry/registryDirectory of all public protocols, ranked & searchable
List APIGET /api/public/scoresJSON list (search/sort/paginate), CORS-open
Protocol APIGET /api/public/scores/{slug}Full JSON: score + per-category breakdown
Metrics APIGET /api/public/statsLive network metrics
Score badge/api/badge/{slug}.svgEmbeddable shields-style badge
Scorecard…?style=cardFull per-category scorecard, one SVG
API explorer/developersInteractive, try-it-live API docs

All read endpoints are no-auth and CORS-open so wallets, explorers, and dashboards can consume them directly. Badges are served live and escape all user-controlled text — a score can neither be faked with a static image nor used as an injection vector.

09Gamification — earned, never bought

Rewards flow only from verifiable improvement, and never touch the score.

Security Points are awarded only for outcomes that make code safer — a rescan-verified fix, a clean PR — never for spend or scan volume. Awards are idempotent (deduped in the database), so re-pushing commits can't farm points. Points drive leagues (Bronze → Titan) and non-purchasable badges.

Workspace XP pet

A per-workspace pixel creature that levels on Security Points and evolves through six stages (Spark Egg → Titan), one per league — a shareable, public engagement layer.

Public standing

A workspace's standing is shareable at /s/{slug} with its own live SVG badge — aggregate engagement data only, never findings.

Firewall
One rule is permanent: points, leagues, and any future token never influence the security score. The score is computed only from scan results.

10GitHub integration

Sign-in, repo access, and label-triggered PR scans.

  • OAuth — "sign in with GitHub" is also the grant to read the user's repos. Sessions are stateless jose HS256 JWTs; the access token is encrypted at rest with AES-256-GCM.
  • GitHub App — one-click manifest creation; authenticates with an RS256 app JWT and mints short-lived installation tokens for repo/PR file access.
  • Webhooks — signed with HMAC and verified in constant time. A PR labeled with the configured scan label enqueues a PR scan; the worker fetches only the PR's changed .sol files and posts results back as a PR comment.
  1. GitHub sends a signed webhook when a PR is labeled.
  2. Kagex verifies the HMAC and resolves the tenant via the installation.
  3. The worker fetches the PR's changed .sol files with an installation token.
  4. It analyzes, scores, and diffs against prior scans of the same PR.
  5. It posts the verdict + findings back as a PR comment.

11Security & multi-tenancy

Every row is org-scoped; every boundary is enforced.

Tenant isolation

All queries are org-scoped. Webhooks resolve the repo via the installation's org (a repo id alone isn't tenant-unique); repo registration verifies push access on GitHub before linking; sessions resolve membership for the signed-in org specifically.

Rate limiting

Redis fixed-window per-IP limits on public & auth endpoints (60/min API, 120/min badges, 20/min auth) plus an in-memory global backstop (300/min) in the proxy. Fail-open — a Redis hiccup never takes the API down.

Cost guard

The expensive AI path is bounded by a per-org monthly scan quota, so no tenant can run up unbounded inference cost.

Injection-safe

Public SVG badges escape all user-controlled text (including quotes) for both text and attribute contexts — no stored-XSS via a repo name.

Volumetric (L3/L4) DDoS is absorbed at the CDN/edge in front of the app; the controls above are the application-layer complement.

12Reliability

Scans are durable jobs, not fire-and-forget requests.

  • Retries — BullMQ retries failed jobs with backoff; only the final attempt marks a scan failed.
  • Stuck-scan sweeper — a periodic sweep fails scans that never finish, timing running scans from when work actually began (not enqueue) and giving pending scans a longer grace.
  • Honest verdicts — partial coverage downgrades a clean pass; an all-agents-failed scan fails rather than reporting "clean".
  • Idempotent side-effects — points awards and lesson writes dedupe at the database layer, so retries and races can't double-count.

13Roadmap

From “review every change” to a security network.

Threat-model generation

Auto-drafted, audit-ready threat models: actors, assets, trust assumptions, privileged actions, and the full attack surface — from the code.

Attack-path simulation

Not "possible reentrancy" — the actual exploit path with an auto-generated Foundry PoC executed in a sandbox: exploit reproduced, funds at risk quantified.

Invariants & fuzzing

Proposed invariants that must hold, plus the generated fuzz harnesses to test them.

Open for Review & bounties

Protocols open a scan to vetted human auditors; AI triage feeds a bug-bounty marketplace. AI finds → humans verify → protocols fund bounties — the security network forms.