::: the handbook

How GitHunt works.

The shape of the platform in plain prose. Trust model, role flows, deployed contracts, state transitions. If you're auditing whether to run a program here, start here.

last revised · 2026-05-23·v0.8·chain 84532 · base sepolia

What is GitHunt

GitHunt is coordinated vulnerability disclosure for the open-source and crypto-developer world, settled on-chain. Researchers find leaks, IDOR, RCE — they report privately to the repo owner. Owners fund a bounty in escrow. Shipping the fix releases the payout. Reputation accrues on-chain.

The platform exists to make the bounty the better deal than any other path a researcher could take. That's the entire product. Everything else — encryption, escrow, SLAs, reputation — is in service of that incentive.

Three roles

  • Researcher — finds an issue, submits an encrypted report, earns $HUNT and on-chain reputation.
  • Owner / Program — a project that runs a bounty program on its repo(s), funds escrow, triages, confirms fixes.
  • Sponsor (v2) — funds standing pools for popular repos or whole ecosystems.

The trust model

Four rules are non-negotiable. Every feature inherits them; if a feature can't be built without breaking one, it doesn't get built.

  • Vuln content is never public. There is no public feed of unresolved reports. Optional sanitized advisories may be published only after a fix, with explicit owner consent.
  • Never stored in plaintext. Reports are end-to-end encrypted client-side to the owner's libsodium public key. The server holds ciphertext + metadata.
  • The platform never tests credentials. Verification is the owner's job. Using a leaked key — even to confirm it — is exactly the line we don't cross.
  • Extortion is forbidden, by design. Reports are private by construction. Pay-or-leak behavior is bond-slashable and reputation-zeroed.

How encryption is wired

Each user generates a libsodium X25519 keypair seeded by a wallet signature over a constant message. The signature is deterministic (RFC-6979 ECDSA), so the same wallet always re-derives the same keypair. Only the public half is uploaded; the private half lives in the browser session.

Researchers seal reports with crypto_box_seal(plaintext, programPubkey) in their browser before submitting. The platform stores ciphertext + SHA-256(plaintext) as contentHash. The hash is committed on-chain at funding time so either party can later prove what was reported without revealing it.

The operator cannot read a reported secret. Not by policy — by construction. Triage happens locally in the owner's browser after they re-derive their keypair.

For researchers

You need three things: a GitHub account, a Base wallet, and a browser that can sign messages.

1 — Open an account

  1. Sign in with GitHub at /connect.
  2. Link your Base wallet by signing a server-issued nonce. The signature proves you control the address — no funds move.
  3. Derive your encryption keypair: sign a fixed message and the browser hashes the signature to a 32-byte seed for X25519. The public half goes to GitHunt; the private half never leaves.

2 — Submit a report

Pick a verified program at /programs. The submit form encrypts your report to the program's public key client-side and computes a content hash. The server only ever sees ciphertext.

You can't re-read a submitted report afterwards — it was sealed to the owner's key, not yours. Keep your content hash if you need proof of what you sent.

3 — Bond & reputation

On mainnet, submitting a report stakes a small $HUNT bond. Valid reports return the bond; spam/bad-faith reports are slashed to the community pool. On release, the escrow contract bumps your on-chain reputation by one — soulbound, weighted by severity in v2.

For program owners

1 — Verify repo control

At /programs/new we call GET /repos/{owner}/{repo} with your GitHub OAuth token and confirm permissions.admin === true. MVP supports public repos only.

2 — Publish scope

You set a markdown scope (in/out of scope, severity rubric) and a reward range. Your encryption pubkey is snapshotted onto the program at creation so future key rotations don't break existing reports.

3 — Triage

Open /me/inbox. Each report shows a status badge, severity claim, and the researcher's GitHub login. Click in, sign the derivation message to recover your private half locally, and decrypt the ciphertext in your browser. Then transition the report: SUBMITTEDTRIAGED ACCEPTED / REJECTED / DUPLICATE.

4 — Fund escrow & release

On an accepted report, the report page renders the Bounty escrow panel. Approve the escrow contract for $HUNT, then call fund(). The report's on-chain id is keccak256(report.id); the content hash is committed alongside. Shipping the fix → click Release bounty → the escrow pays the researcher and bumps their reputation. Refund is available until release.

Contracts on Base

All four contracts are deployed on Base Sepolia (chain 84532). Bytecode is verifiable from source in contracts/src/. The platform is non-custodial: bounty funds move from owner wallet → escrow → researcher wallet. GitHunt never touches them.

HuntToken
$HUNT · ERC-20 · 1B fixed
0x1F4ec0C511621764A29a10663485e14b29972802
HuntEscrow
per-report bounty · fund / release / refund
0xA3cd74FD6085D0967d8C31666af3E1723d9DB349
HuntBond
anti-spam stake · admin slash
0x80c220700d748FEBd1FC619027aa726E1bEFaF46
HuntReputation
soulbound · owner = HuntEscrow
0xeB94a0DAa5cDaC6bA982c83A8ef7D235d6fFd9A0

API & state machine

A Report row carries a status from this enum. Owner triage moves it through the upper rail; chain events drive the lower rail. The worker indexer polls HuntEscrow.Funded / Released / Refunded every 10s and reflects the chain state back into the DB.

enum ReportStatus {
  SUBMITTED   // initial; researcher just sealed it
  TRIAGED     // owner has looked at it
  ACCEPTED    // valid · in scope · awaiting escrow
  REJECTED    // not in scope / not valid
  DUPLICATE   // already reported

  // chain-driven from here:
  ESCROWED    // owner has funded HuntEscrow
  RESOLVED    // fix shipped (v2 — Phase 9+)
  PAID        // escrow released to researcher
  DISPUTED    // arbitration (v2)
  EXPIRED     // SLA breach — worker auto-flags
}

Owner-actionable transitions (manual via API):

SUBMITTED → { TRIAGED, ACCEPTED, REJECTED, DUPLICATE }
TRIAGED   → { ACCEPTED, REJECTED, DUPLICATE }

Chain-driven transitions (indexer-emitted):

ACCEPTED  → ESCROWED   (HuntEscrow.Funded)
ESCROWED  → PAID       (HuntEscrow.Released)
(any)     → audit-only (HuntEscrow.Refunded)

Roadmap

GitHunt ships in nine phases. Phases 1–8 are live; phase 9 is the Railway production deploy + custom domain.

  1. P-01Scaffolddone
  2. P-02Auth + identitydone
  3. P-03Crypto packagedone
  4. P-04Programsdone
  5. P-05Reportingdone
  6. P-06Worker (SLA, notifications, indexer)done
  7. P-07Contracts (4 deployed)done
  8. P-08Escrow integrationdone
  9. P-09Railway deploy + domainin progress
GitHunt

Coordinated vulnerability disclosure, settled on-chain.
The bounty is the better deal.

githunt · v0.8·chain 84532 · base sepolia·$HUNT · 1B fixed·phase 8 / 9

::: vuln content is never public · never stored in plaintext · never tested by the platform