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
- Sign in with GitHub at /connect.
- Link your Base wallet by signing a server-issued nonce. The signature proves you control the address — no funds move.
- 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: SUBMITTED → TRIAGED → 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.
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.
- P-01Scaffolddone
- P-02Auth + identitydone
- P-03Crypto packagedone
- P-04Programsdone
- P-05Reportingdone
- P-06Worker (SLA, notifications, indexer)done
- P-07Contracts (4 deployed)done
- P-08Escrow integrationdone
- P-09Railway deploy + domainin progress
