Skip to content

JRBusiness/Dup-Scout

Repository files navigation

Dup-Scout

Dup-Scout checks whether a bug bounty finding looks like prior art before you write the report. Point it at a GitHub repo, describe the finding, and it scans PRs, issues, commits, releases, and web3 audit sources for likely duplicate, known issue, or already fixed matches.

Install

npm install -g dup-scout
# or run without installing:
npx dup-scout <owner/repo> --title "..." --desc "..."

Auth

Dup-Scout resolves a GitHub token from (in order): --token, GITHUB_TOKEN, GH_TOKEN, then gh auth token. Unauthenticated runs work but hit low rate limits. A read-only token is sufficient.

Usage

dup-scout acme/vault \
  --title "Reentrancy in claim lets attacker drain" \
  --desc "claim() reenters via _settle before state update" \
  --file src/Vault.sol --function claim --scope-tag v1.2.0

# structured finding from a file:
dup-scout acme/vault --finding finding.md --markdown

# CI gate: exit non-zero if it looks like a duplicate
dup-scout acme/vault --finding finding.md --fail-on DUPLICATE

# preview the queries without calling GitHub, as JSON
dup-scout acme/vault --title "..." --keys claim,_settle --dry-run --json

Options

Flag Description
--title <s> Finding title (required unless --finding is used)
--desc <s> Finding description
--finding <file> Load the finding from a .json or .md file
--file <path> Affected source file
--function <name> Affected function name(s); repeatable
--keys <a,b,c> Extra search keys (comma-separated)
--scope-tag <tag> In-scope tag for silent-fix detection
--bug-class <s> Bug class (e.g. reentrancy)
--sources <ids> Comma-separated source ids to enable
--min-score <n> Minimum match score to report (numeric)
--json Output JSON
--markdown Output a markdown "Duplicate check" block
--dry-run Print the queries that would run without calling the API
--token <t> GitHub token override
--fail-on <label> Exit non-zero at/above this verdict (NOVEL through DUPLICATE)

Invalid --fail-on labels and non-numeric --min-score values exit with a non-zero status instead of being silently ignored.

Finding markdown format

# Reentrancy in claim lets attacker drain

claim() reenters via _settle before the balance is updated.

File: src/Vault.sol
Functions: claim, _settle
Scope-Tag: v1.2.0
Bug-Class: reentrancy

Verdicts

Verdict Meaning
DUPLICATE Same function + root cause already in a merged PR / closed issue / contest finding
KNOWN-ISSUE Acknowledged / won't-fix in a past audit report
SILENTLY-FIXED Affected file changed after your in-scope tag (check the program's undeployed-fix rules)
PARTIAL-OVERLAP Same bug class, different location; argue distinctness
NOVEL No qualifying prior art found in enabled sources

Sources

github-prs, github-issues, github-commits, github-releases, github-code, audit-reports, contests (guided). Enable a subset with --sources github-prs,audit-reports.

The contests source is guided: it emits candidate Code4rena / Sherlock / Cantina / Immunefi search URLs to check manually. Provide a fetch hook via the library API to auto-scan them.

Agent integration (Claude Code & Codex)

Register a /dup-scout slash command inside both agents so you can run a duplicate check without leaving your session:

dup-scout install --all     # installs into both Claude Code and Codex
dup-scout install           # same as --all when no agent flag is given
dup-scout install --claude  # Claude Code only  (~/.claude/commands/dup-scout.md)
dup-scout install --codex   # Codex only         (~/.codex/prompts/dup-scout.md)
dup-scout install --force   # overwrite existing command files

install honours CLAUDE_CONFIG_DIR and CODEX_HOME if set. It never runs on npm install; it only runs when you call it. Then, inside either agent:

/dup-scout acme/vault reentrancy in claim() lets an attacker drain the vault

The command shells out to the dup-scout CLI (install it globally first with npm i -g dup-scout) and summarizes the verdict.

Benchmark

Dup-Scout includes a deterministic benchmark for recall and verdict accuracy:

npm run bench        # replay recorded fixtures, compute Recall@K + verdict accuracy (CI gate)
npm run bench:live   # re-fetch from GitHub and refresh fixtures (needs a token)

Cases live in benchmark/cases/, recorded responses in benchmark/fixtures/, and metric floors in benchmark/thresholds.json.

Library use

import { run } from "dup-scout";
const verdict = await run({ repo: "acme/vault", finding: { title: "...", description: "..." } });

Caveats

Dup-Scout estimates duplicate likelihood; it is not a substitute for reading the program's scope, known-issues list, and prior-audit clause. Always confirm matches by hand before deciding not to submit.

License

MIT

About

Prior-art / duplicate checker for bug bounty findings.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages