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.
npm install -g dup-scout
# or run without installing:
npx dup-scout <owner/repo> --title "..." --desc "..."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.
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| 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.
# 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| 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 |
github-prs, github-issues, github-commits, github-releases, github-code, audit-reports, contests (guided). Enable a subset with --sources github-prs,audit-reports.
The
contestssource 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.
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 filesinstall 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.
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.
import { run } from "dup-scout";
const verdict = await run({ repo: "acme/vault", finding: { title: "...", description: "..." } });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.
MIT