bug-bounty-intelligence-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Dockerfile ADDED
@@ -0,0 +1,6 @@
1
+ FROM node:20-slim
2
+ WORKDIR /app
3
+ COPY package.json .
4
+ RUN npm install
5
+ COPY . .
6
+ CMD ["node", "index.mjs"]
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # Bug Bounty Intelligence — MCP Server
2
+
3
+ AI-powered smart contract security analysis for AI agents and developers.
4
+
5
+ **Trained on 27,681 real audit findings from Sherlock and Code4rena.**
6
+ **Cost: $5 USDC on Base (eip155:8453) via x402.**
7
+ **Free tool: `list_vulnerability_patterns` — no payment needed.**
8
+
9
+ ## What it does
10
+
11
+ Submit a public GitHub repo containing Solidity smart contracts. Receive a full vulnerability report within 24 hours, powered by the Al-Mizaan v3 analysis framework.
12
+
13
+ ## Tools
14
+
15
+ | Tool | Description | Cost |
16
+ |------|-------------|------|
17
+ | `scan_contract` | Submit repo for security analysis | $5 USDC |
18
+ | `get_scan_report` | Poll status and get report URL | Free |
19
+ | `list_vulnerability_patterns` | Show historical acceptance rates from 27K findings | Free |
20
+
21
+ ## Quick start (Claude Desktop / Claude Code)
22
+
23
+ Add to your `claude_desktop_config.json`:
24
+
25
+ ```json
26
+ {
27
+ "mcpServers": {
28
+ "bug-bounty-intelligence": {
29
+ "command": "npx",
30
+ "args": ["-y", "github:holistis/bug-bounty-intelligence-mcp"]
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ Or run directly:
37
+
38
+ ```bash
39
+ node index.mjs
40
+ ```
41
+
42
+ ## Payment
43
+
44
+ If `scan_contract` returns `PAYMENT REQUIRED`, send exactly $5 USDC on Base to the address shown, then retry. Payment = acceptance of [service terms](https://wazir-x402.duckdns.org/terms).
45
+
46
+ **x402 info:**
47
+ - Network: Base mainnet (eip155:8453)
48
+ - Amount: 5,000,000 (= 5 USDC, 6 decimals)
49
+ - Asset: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 (USDC)
50
+ - Wallet: 0xdffcC75a674257be6FE1b5549FE52e8f8a6A3A5A
51
+
52
+ ## Example session
53
+
54
+ ```
55
+ > list_vulnerability_patterns({ protocol_type: "LENDING" })
56
+
57
+ Vulnerability patterns for LENDING protocols (from 27,681 real audit findings):
58
+
59
+ oracle-manipulation 53% accepted (3253 cases)
60
+ liquidation 53% accepted (2502 cases)
61
+ staleness 45% accepted (5838 cases)
62
+ rounding 51% accepted (2615 cases)
63
+ flash-loan 53% accepted (512 cases)
64
+ access-control 51% accepted (2480 cases)
65
+
66
+ > scan_contract({ repo_url: "https://github.com/myprotocol/contracts", protocol_type: "LENDING" })
67
+
68
+ PAYMENT REQUIRED to start the scan.
69
+
70
+ Amount: 5.00 USDC
71
+ Network: Base mainnet (eip155:8453)
72
+ Pay to: 0xdffcC75a674257be6FE1b5549FE52e8f8a6A3A5A
73
+ Asset: USDC — 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
74
+
75
+ After paying, retry scan_contract with the same repo_url.
76
+ ```
77
+
78
+ ## Sample scan output
79
+
80
+ Real scan of `sherlock-audit/2025-03-crestal-network` (Derivatives protocol, 29 contracts):
81
+
82
+ ```
83
+ Summary: 0 Critical | 1 High | 0 Medium | 0 Low
84
+ Analyzed: 29 contracts | Model: qwen2.5:7b | Duration: 25min
85
+
86
+ FINDING #1 — HIGH
87
+ Title: Owner Can Arbitrarily Set Payment Addresses
88
+ File: Blueprint.sol
89
+ Functions: setCreateAgentTokenCost, setUpdateCreateAgentTokenCost,
90
+ addPaymentAddress, removePaymentAddress
91
+ Category: ACCESS
92
+
93
+ Description:
94
+ The owner can arbitrarily set payment addresses and costs without
95
+ any external validation or timelock.
96
+
97
+ Attack path:
98
+ An attacker with ownership calls setCreateAgentTokenCost or
99
+ addPaymentAddress to modify fees or redirect user payments to
100
+ an attacker-controlled wallet.
101
+
102
+ Impact:
103
+ Extremely high costs (griefing) or redirection of user funds.
104
+
105
+ Recommendation:
106
+ Implement a governance mechanism or timelock to restrict fee
107
+ and address changes.
108
+
109
+ Confidence: 0.90 (CONFIRMED by Al-Mizaan validation)
110
+ ```
111
+
112
+ ## About the analysis
113
+
114
+ The Al-Mizaan v3 framework checks 7 gates:
115
+
116
+ 1. Code reading (literal, not docs)
117
+ 2. Reachability chain (entry to exploit)
118
+ 3. Threat model (who can trigger it)
119
+ 4. Invariant breach (what rule is violated)
120
+ 5. Protocol intent (was this intended?)
121
+ 6. Impact (real financial damage)
122
+ 7. Formal proof (reproducible PoC)
123
+
124
+ Only findings that survive all 7 gates are reported.
125
+
126
+ ## Service info
127
+
128
+ - **API endpoint**: https://wazir-x402.duckdns.org/api/bug-intel
129
+ - **Terms**: https://wazir-x402.duckdns.org/terms
130
+ - **Delivery**: within 24h
131
+ - **Source code**: deleted after analysis
package/index.mjs ADDED
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Bug Bounty Intelligence — MCP Server
4
+ *
5
+ * Tools:
6
+ * scan_contract(repo_url, protocol_type?) → submit for analysis, returns job_id
7
+ * get_scan_report(job_id) → poll status + get report URL
8
+ * list_vulnerability_patterns(protocol?) → show historical patterns from 27K findings
9
+ *
10
+ * Payment: $5 USDC on Base (eip155:8453) via x402.
11
+ * If you receive a payment_required response, pay to the address shown and retry.
12
+ *
13
+ * Run: node scripts/bug-intel-mcp.mjs
14
+ */
15
+
16
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js'
17
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
18
+ import {
19
+ CallToolRequestSchema,
20
+ ListToolsRequestSchema,
21
+ } from '@modelcontextprotocol/sdk/types.js'
22
+ import { readFileSync, existsSync } from 'node:fs'
23
+ import { join, dirname } from 'node:path'
24
+ import { fileURLToPath } from 'node:url'
25
+
26
+ const HERE = dirname(fileURLToPath(import.meta.url))
27
+ const BASE = join(HERE, '..')
28
+ const API_URL = 'https://wazir-x402.duckdns.org'
29
+
30
+ // ── helpers ──────────────────────────────────────────────────────────────────
31
+
32
+ async function callApi(path, method = 'GET', body = null, extraHeaders = {}) {
33
+ const opts = {
34
+ method,
35
+ headers: { 'Content-Type': 'application/json', ...extraHeaders },
36
+ signal: AbortSignal.timeout(30_000),
37
+ }
38
+ if (body) opts.body = JSON.stringify(body)
39
+ const res = await fetch(`${API_URL}${path}`, opts)
40
+ const text = await res.text()
41
+ let json
42
+ try { json = JSON.parse(text) } catch { json = { raw: text } }
43
+ return { status: res.status, ok: res.ok, json }
44
+ }
45
+
46
+ function ilmPatterns(protocolType) {
47
+ const idx = join(BASE, 'knowledge/3ilm/sherlock/_index.json')
48
+ if (!existsSync(idx)) return null
49
+ try {
50
+ const lib = JSON.parse(readFileSync(idx, 'utf8')).pattern_library ?? {}
51
+ const TYPE = {
52
+ DEX: ['oracle-manipulation','mev-slippage','rounding','flash-loan','fee-miscalculation','reentrancy'],
53
+ LENDING: ['oracle-manipulation','liquidation','staleness','rounding','flash-loan','access-control'],
54
+ BRIDGE: ['access-control','reentrancy','overflow','dos-griefing'],
55
+ GOVERNANCE: ['access-control','dos-griefing','trusted-actor'],
56
+ STAKING: ['rounding','fee-miscalculation','access-control','overflow','staleness'],
57
+ GENERAL: ['oracle-manipulation','rounding','access-control','fee-miscalculation','reentrancy','flash-loan'],
58
+ }
59
+ const keys = TYPE[protocolType?.toUpperCase()] ?? TYPE.GENERAL
60
+ return keys.filter(k => lib[k]).map(k => ({
61
+ pattern: k,
62
+ acceptance_rate: lib[k].acceptance_rate,
63
+ total_cases: lib[k].total,
64
+ example: (lib[k].examples_accepted ?? [])[0]?.slice(0, 120),
65
+ }))
66
+ } catch { return null }
67
+ }
68
+
69
+ // ── MCP server ────────────────────────────────────────────────────────────────
70
+
71
+ const server = new Server(
72
+ { name: 'bug-bounty-intelligence', version: '1.0.0' },
73
+ { capabilities: { tools: {} } }
74
+ )
75
+
76
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
77
+ tools: [
78
+ {
79
+ name: 'scan_contract',
80
+ description: [
81
+ 'Submit a public GitHub repository for an automated smart contract security analysis.',
82
+ 'Trained on 27,681 real findings from Sherlock and Code4rena audits.',
83
+ 'Cost: $5 USDC on Base (eip155:8453) via x402.',
84
+ 'Returns a job_id. Use get_scan_report to poll for results (ready within 24h).',
85
+ 'If payment_required is true, pay $5 USDC to the payTo address on Base, then retry.',
86
+ ].join(' '),
87
+ inputSchema: {
88
+ type: 'object',
89
+ properties: {
90
+ repo_url: {
91
+ type: 'string',
92
+ description: 'Public GitHub repo URL containing Solidity contracts (e.g. https://github.com/org/repo)',
93
+ },
94
+ protocol_type: {
95
+ type: 'string',
96
+ enum: ['DEX', 'LENDING', 'BRIDGE', 'GOVERNANCE', 'STAKING', 'DERIVATIVES', 'GENERAL'],
97
+ description: 'Protocol category for targeted analysis (optional, default GENERAL)',
98
+ },
99
+ },
100
+ required: ['repo_url'],
101
+ },
102
+ },
103
+ {
104
+ name: 'get_scan_report',
105
+ description: 'Poll the status of a previously submitted scan. Returns status (queued/processing/complete) and report URL when complete.',
106
+ inputSchema: {
107
+ type: 'object',
108
+ properties: {
109
+ job_id: { type: 'string', description: 'The job_id returned by scan_contract' },
110
+ },
111
+ required: ['job_id'],
112
+ },
113
+ },
114
+ {
115
+ name: 'list_vulnerability_patterns',
116
+ description: [
117
+ 'Returns historical vulnerability patterns and their acceptance rates from 27,681 real audit findings.',
118
+ 'Useful for understanding what types of bugs are most likely to be valid in a given protocol type.',
119
+ 'This tool is FREE — no payment required.',
120
+ ].join(' '),
121
+ inputSchema: {
122
+ type: 'object',
123
+ properties: {
124
+ protocol_type: {
125
+ type: 'string',
126
+ enum: ['DEX', 'LENDING', 'BRIDGE', 'GOVERNANCE', 'STAKING', 'DERIVATIVES', 'GENERAL'],
127
+ description: 'Protocol type to filter patterns (default GENERAL)',
128
+ },
129
+ },
130
+ },
131
+ },
132
+ ],
133
+ }))
134
+
135
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
136
+ const { name, arguments: args } = req.params
137
+
138
+ // ── scan_contract ──────────────────────────────────────────────────────────
139
+ if (name === 'scan_contract') {
140
+ const { repo_url, protocol_type = 'GENERAL' } = args ?? {}
141
+ if (!repo_url) {
142
+ return { content: [{ type: 'text', text: 'Error: repo_url is required' }], isError: true }
143
+ }
144
+
145
+ const { status, json } = await callApi('/api/bug-intel', 'POST', { repo: repo_url, protocolType: protocol_type })
146
+
147
+ if (status === 402) {
148
+ const accept = json.accepts?.[0] ?? {}
149
+ const amtUsdc = accept.amount ? (parseInt(accept.amount) / 1_000_000).toFixed(2) : '5.00'
150
+ return {
151
+ content: [{
152
+ type: 'text',
153
+ text: [
154
+ 'PAYMENT REQUIRED to start the scan.',
155
+ '',
156
+ `Amount: ${amtUsdc} USDC`,
157
+ `Network: Base mainnet (eip155:8453)`,
158
+ `Pay to: ${accept.payTo ?? '0xdffcC75a674257be6FE1b5549FE52e8f8a6A3A5A'}`,
159
+ `Asset: USDC — ${accept.asset ?? '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'}`,
160
+ '',
161
+ 'After paying, retry scan_contract with the same repo_url.',
162
+ 'Terms: https://wazir-x402.duckdns.org/terms',
163
+ ].join('\n'),
164
+ }],
165
+ isError: false,
166
+ }
167
+ }
168
+
169
+ if (status === 200 || status === 201) {
170
+ return {
171
+ content: [{
172
+ type: 'text',
173
+ text: [
174
+ `Scan submitted. Job ID: ${json.jobId}`,
175
+ `Status: ${json.status ?? 'queued'}`,
176
+ '',
177
+ `Poll for results: get_scan_report({ job_id: "${json.jobId}" })`,
178
+ `Results are typically ready within 24 hours.`,
179
+ ].join('\n'),
180
+ }],
181
+ }
182
+ }
183
+
184
+ return {
185
+ content: [{ type: 'text', text: `API error ${status}: ${JSON.stringify(json).slice(0, 300)}` }],
186
+ isError: true,
187
+ }
188
+ }
189
+
190
+ // ── get_scan_report ────────────────────────────────────────────────────────
191
+ if (name === 'get_scan_report') {
192
+ const { job_id } = args ?? {}
193
+ if (!job_id) {
194
+ return { content: [{ type: 'text', text: 'Error: job_id is required' }], isError: true }
195
+ }
196
+
197
+ const { status, json } = await callApi(`/api/bug-intel/${encodeURIComponent(job_id)}`)
198
+
199
+ if (status === 404) {
200
+ return { content: [{ type: 'text', text: `Job ${job_id} not found. Check the job_id.` }], isError: true }
201
+ }
202
+
203
+ const lines = [`Job ID: ${job_id}`, `Status: ${json.status ?? 'unknown'}`]
204
+ if (json.repo) lines.push(`Repo: ${json.repo}`)
205
+ if (json.reportUrl) lines.push(`Report: ${json.reportUrl}`)
206
+ if (json.findingsCount !== undefined) lines.push(`Findings: ${json.findingsCount}`)
207
+ if (json.status === 'queued' || json.status === 'processing') {
208
+ lines.push('', 'Analysis in progress. Try again in a few minutes.')
209
+ }
210
+
211
+ return { content: [{ type: 'text', text: lines.join('\n') }] }
212
+ }
213
+
214
+ // ── list_vulnerability_patterns ───────────────────────────────────────────
215
+ if (name === 'list_vulnerability_patterns') {
216
+ const { protocol_type = 'GENERAL' } = args ?? {}
217
+ const patterns = ilmPatterns(protocol_type)
218
+
219
+ if (!patterns) {
220
+ return {
221
+ content: [{ type: 'text', text: 'Pattern library not available locally. Run scan_contract for live analysis.' }],
222
+ }
223
+ }
224
+
225
+ const lines = [`Vulnerability patterns for ${protocol_type} protocols (from 27,681 real audit findings):`, '']
226
+ for (const p of patterns) {
227
+ const pct = Math.round(parseFloat(p.acceptance_rate) * 100)
228
+ lines.push(`${p.pattern.padEnd(24)} ${pct}% accepted (${p.total_cases} cases)`)
229
+ if (p.example) lines.push(` Example: ${p.example}`)
230
+ }
231
+ lines.push('', 'Run scan_contract to check your contracts against these patterns.')
232
+
233
+ return { content: [{ type: 'text', text: lines.join('\n') }] }
234
+ }
235
+
236
+ return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true }
237
+ })
238
+
239
+ // ── start ─────────────────────────────────────────────────────────────────────
240
+
241
+ const transport = new StdioServerTransport()
242
+ await server.connect(transport)
243
+ // server runs until process exits
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "bug-bounty-intelligence-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for AI-powered smart contract security analysis. $5 USDC/scan via x402. Trained on 27,681 real Sherlock/Code4rena findings.",
5
+ "type": "module",
6
+ "main": "index.mjs",
7
+ "bin": { "bug-bounty-intelligence-mcp": "index.mjs" },
8
+ "keywords": ["mcp", "smart-contract", "security", "audit", "solidity", "defi", "x402", "bug-bounty"],
9
+ "author": "holistis",
10
+ "license": "MIT",
11
+ "dependencies": {
12
+ "@modelcontextprotocol/sdk": "^1.29.0"
13
+ },
14
+ "engines": { "node": ">=20.0.0" }
15
+ }
package/smithery.yaml ADDED
@@ -0,0 +1,9 @@
1
+ # Smithery configuration: https://smithery.ai/docs/config#smitheryyaml
2
+
3
+ startCommand:
4
+ type: stdio
5
+ configSchema:
6
+ type: object
7
+ properties: {}
8
+ commandFunction: |-
9
+ (config) => ({command: 'node', args: ['index.mjs'], env: {}})