agentaudit 3.13.4 → 3.13.6

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/README.md CHANGED
@@ -77,18 +77,18 @@ agentaudit lookup fastmcp
77
77
 
78
78
  **Example output:**
79
79
  ```
80
- AgentAudit v3.12.9 │ my-scanner #3 · 280pts · 19 audits
80
+ AgentAudit v3.13.4 │ my-scanner · #3 · 280pts · 19 audits
81
81
 
82
82
  Discovering MCP servers in your AI editors...
83
83
 
84
84
  • Scanning Cursor ~/.cursor/mcp.json found 3 servers
85
85
 
86
86
  ├── tool supabase-mcp ✔ ok
87
- │ SAFE Risk 0 https://agentaudit.dev/skills/supabase-mcp
87
+ │ SAFE Risk 0 https://agentaudit.dev/packages/supabase-mcp
88
88
  ├── tool browser-tools-mcp ✔ ok
89
89
  │ ⚠ not audited Run: agentaudit audit https://github.com/nichochar/browser-tools-mcp
90
90
  └── tool filesystem ✔ ok
91
- │ SAFE Risk 0 https://agentaudit.dev/skills/filesystem
91
+ │ SAFE Risk 0 https://agentaudit.dev/packages/filesystem
92
92
 
93
93
  Looking for general package scanning? Try `pip audit` or `npm audit`.
94
94
  ```
@@ -210,7 +210,11 @@ Then ask your agent: *"Check which MCP servers I have installed and audit any un
210
210
  | `agentaudit scan <url>` | Quick regex-based static scan (~2s) | `agentaudit scan https://github.com/owner/repo` |
211
211
  | `agentaudit scan <url> --deep` | Deep audit (same as `audit`) | `agentaudit scan https://github.com/owner/repo --deep` |
212
212
  | `agentaudit audit <url>` | Deep LLM-powered 3-pass audit (~30s) | `agentaudit audit https://github.com/owner/repo` |
213
+ | `agentaudit audit <url> --verify` | Audit + adversarial verification pass (reduces false positives) | `agentaudit audit <url> --verify self` |
214
+ | `agentaudit audit <url> --remote` | Server-side scan via agentaudit.dev (no LLM key needed, 3/day free) | `agentaudit audit <url> --remote` |
215
+ | `agentaudit consensus <name>` | Cross-model consensus view for a package | `agentaudit consensus supabase-mcp` |
213
216
  | `agentaudit lookup <name>` | Look up package in trust registry | `agentaudit lookup fastmcp` |
217
+ | `agentaudit history` | Show local audit history | `agentaudit history` |
214
218
 
215
219
  ### Community
216
220
 
@@ -238,6 +242,10 @@ Then ask your agent: *"Check which MCP servers I have installed and audit any un
238
242
  | `--quiet` / `-q` | Suppress banner and decorative output |
239
243
  | `--no-color` | Disable ANSI colors (also respects `NO_COLOR` env var) |
240
244
  | `--model <name>` | Override LLM model for this run |
245
+ | `--models <a,b,c>` | Multi-model audit (parallel calls, consensus comparison) |
246
+ | `--verify <mode>` | Adversarial verification: `self` (same model), `cross` (different model), or `<model-name>` |
247
+ | `--no-verify` | Skip verification even if configured |
248
+ | `--remote` | Use agentaudit.dev server for scan (no local LLM key needed) |
241
249
  | `--no-upload` | Skip uploading report to registry |
242
250
  | `--export` | Export audit payload as markdown |
243
251
  | `--debug` | Show raw LLM response on parse errors |
@@ -279,6 +287,9 @@ When running as an MCP server, AgentAudit exposes the following tools to your AI
279
287
  | `check_registry` | Look up a package in the trust registry |
280
288
  | `submit_report` | Upload audit findings to the registry |
281
289
  | `discover_servers` | Find MCP servers in local editor configs |
290
+ | `consensus_analysis` | Cross-model consensus view for a package |
291
+ | `search_packages` | Search packages in the registry by name, ASF-ID, or hash |
292
+ | `scan_tool_poisoning` | Detect tool poisoning in MCP tool descriptions |
282
293
 
283
294
  ### Workflow
284
295
 
@@ -383,6 +394,34 @@ The deep audit (`agentaudit audit`) uses a structured 3-phase LLM analysis — n
383
394
 
384
395
  This architecture achieved **0% false positives** on our 11-package test set, down from 42% in v2.
385
396
 
397
+ ### Adversarial Verification Pass (v3.13+)
398
+
399
+ After the 3-pass audit, an optional **verification pass** re-examines each finding against the actual source code:
400
+
401
+ ```bash
402
+ agentaudit audit https://github.com/owner/repo --verify self
403
+ ```
404
+
405
+ Each finding goes through a 5-point checklist:
406
+ 1. **Code Existence** — Does the cited code actually exist in the file?
407
+ 2. **Context Accuracy** — Is the code used in the way described?
408
+ 3. **Execution Model** — Can an attacker actually trigger this?
409
+ 4. **Severity Calibration** — Is the severity appropriate?
410
+ 5. **Fabrication Check** — Are there hallucinated details?
411
+
412
+ Verdicts: `verified` (confirmed real), `demoted` (severity reduced), `rejected` (false positive removed).
413
+
414
+ ### Model Accuracy (Real-World Data)
415
+
416
+ We benchmarked multiple LLMs on the **Top 20 most popular MCP servers** (62+ reports):
417
+
418
+ | Model | Findings on Top 20 | Precision | Assessment |
419
+ |-------|-------------------|-----------|------------|
420
+ | **Claude Opus 4.6** | 0 findings (all clean) | N/A | Very conservative — ideal for avoiding false positives |
421
+ | **Gemini 2.5 Flash** | Many findings | ~30% strict | High false positive rate — not recommended for production audits |
422
+
423
+ > **Key insight:** Model choice dramatically affects audit quality. We recommend Claude Opus 4 or Claude Sonnet 4 for production audits. Use `--models` to run multiple models and compare results via `consensus`.
424
+
386
425
  ---
387
426
 
388
427
  ## 🔄 CI/CD Integration
@@ -450,11 +489,12 @@ AgentAudit includes a full-screen interactive dashboard and standalone community
450
489
  agentaudit dashboard # or: agentaudit dash
451
490
  ```
452
491
 
453
- 5-tab TUI with keyboard navigation (←→ tabs, ↑↓ scroll, 1-5 jump, q quit):
492
+ 5-tab TUI with keyboard navigation (←→ tabs, ↑↓ scroll, 1-5 jump, q quit).
493
+ Overview tab includes **interactive Quick Actions** — select and launch audits, consensus views, or remote scans directly from the dashboard:
454
494
 
455
495
  | Tab | Content |
456
496
  |-----|---------|
457
- | **[1] Overview** | Your profile (rank, points, audits, severity breakdown) + registry stats |
497
+ | **[1] Overview** | Your profile + registry stats + interactive Quick Actions (press a/v/r/c or Enter) |
458
498
  | **[2] Leaderboard** | Top contributors with medal rankings and bar charts |
459
499
  | **[3] Benchmark** | LLM model audit performance comparison |
460
500
  | **[4] Activity** | Your recent audits and findings |
package/cli.mjs CHANGED
@@ -64,7 +64,7 @@ const LLM_PROVIDERS = [
64
64
  { key: 'DEEPSEEK_API_KEY', name: 'DeepSeek', provider: 'deepseek', type: 'openai', model: 'deepseek-chat', url: 'https://api.deepseek.com/v1/chat/completions' },
65
65
  { key: 'MISTRAL_API_KEY', name: 'Mistral', provider: 'mistral', type: 'openai', model: 'mistral-large-latest', url: 'https://api.mistral.ai/v1/chat/completions' },
66
66
  { key: 'GROQ_API_KEY', name: 'Groq', provider: 'groq', type: 'openai', model: 'llama-3.3-70b-versatile', url: 'https://api.groq.com/openai/v1/chat/completions' },
67
- { key: 'XAI_API_KEY', name: 'xAI (Grok)', provider: 'xai', type: 'openai', model: 'grok-3', url: 'https://api.x.ai/v1/chat/completions' },
67
+ { key: 'XAI_API_KEY', name: 'xAI (Grok)', provider: 'xai', type: 'openai', model: 'grok-4', url: 'https://api.x.ai/v1/chat/completions' },
68
68
  { key: 'TOGETHER_API_KEY', name: 'Together AI', provider: 'together', type: 'openai', model: 'meta-llama/Llama-3.3-70B-Instruct-Turbo', url: 'https://api.together.xyz/v1/chat/completions' },
69
69
  { key: 'FIREWORKS_API_KEY', name: 'Fireworks AI', provider: 'fireworks', type: 'openai', model: 'accounts/fireworks/models/llama-v3p3-70b-instruct', url: 'https://api.fireworks.ai/inference/v1/chat/completions' },
70
70
  { key: 'CEREBRAS_API_KEY', name: 'Cerebras', provider: 'cerebras', type: 'openai', model: 'llama-3.3-70b', url: 'https://api.cerebras.ai/v1/chat/completions' },
@@ -78,15 +78,16 @@ const LLM_PROVIDERS = [
78
78
  const PROVIDER_MODELS = {
79
79
  anthropic: [
80
80
  { label: 'claude-sonnet-4-20250514', sublabel: 'fast + smart (default)', value: 'claude-sonnet-4-20250514' },
81
- { label: 'claude-opus-4-20250514', sublabel: 'most capable', value: 'claude-opus-4-20250514' },
81
+ { label: 'claude-opus-4-20250514', sublabel: 'best precision (recommended for audits)', value: 'claude-opus-4-20250514' },
82
82
  ],
83
83
  openai: [
84
84
  { label: 'gpt-4o', sublabel: 'fast multimodal (default)', value: 'gpt-4o' },
85
- { label: 'gpt-4.1', sublabel: 'latest', value: 'gpt-4.1' },
85
+ { label: 'gpt-4.1', sublabel: 'large context (low recall on audits)', value: 'gpt-4.1' },
86
86
  ],
87
87
  google: [
88
88
  { label: 'gemini-2.5-flash', sublabel: 'fast + cheap (default)', value: 'gemini-2.5-flash' },
89
- { label: 'gemini-2.5-pro', sublabel: 'most capable', value: 'gemini-2.5-pro' },
89
+ { label: 'gemini-2.5-pro', sublabel: 'strong reasoning', value: 'gemini-2.5-pro' },
90
+ { label: 'gemini-3.1-pro', sublabel: 'best detection (recommended for audits)', value: 'gemini-3.1-pro' },
90
91
  ],
91
92
  deepseek: [
92
93
  { label: 'deepseek-chat', sublabel: 'cost-effective (default)', value: 'deepseek-chat' },
@@ -98,7 +99,8 @@ const PROVIDER_MODELS = {
98
99
  { label: 'llama-3.3-70b-versatile', sublabel: 'ultra-fast (default)', value: 'llama-3.3-70b-versatile' },
99
100
  ],
100
101
  xai: [
101
- { label: 'grok-3', sublabel: 'real-time knowledge (default)', value: 'grok-3' },
102
+ { label: 'grok-4', sublabel: 'best detection (default, recommended)', value: 'grok-4' },
103
+ { label: 'grok-3', sublabel: 'faster, lower cost', value: 'grok-3' },
102
104
  ],
103
105
  together: [
104
106
  { label: 'meta-llama/Llama-3.3-70B-Instruct-Turbo', sublabel: 'open source (default)', value: 'meta-llama/Llama-3.3-70B-Instruct-Turbo' },
@@ -267,6 +269,14 @@ function resolveProvider() {
267
269
  }
268
270
 
269
271
  function resolveModel(modelName) {
272
+ // Shorthand aliases for recommended models
273
+ const aliases = {
274
+ 'opus': 'claude-opus-4-20250514',
275
+ 'sonnet': 'claude-sonnet-4-20250514',
276
+ 'gemini-3.1-pro': 'google/gemini-3.1-pro-preview',
277
+ 'gemini-3.1-flash': 'google/gemini-3.1-flash-preview',
278
+ };
279
+ if (aliases[modelName.toLowerCase()]) modelName = aliases[modelName.toLowerCase()];
270
280
  // model with '/' → OpenRouter
271
281
  if (modelName.includes('/')) {
272
282
  const p = LLM_PROVIDERS.find(p => p.provider === 'openrouter' && process.env[p.key]);
@@ -2812,18 +2822,26 @@ Decision rules: code_exists=false→REJECTED; code_matches_description=false→R
2812
2822
 
2813
2823
  // Known context window sizes (input tokens) for common models
2814
2824
  const MODEL_CONTEXT_LIMITS = {
2825
+ 'claude-sonnet-4-6': 200000, 'claude-opus-4-6': 200000,
2815
2826
  'claude-sonnet-4': 200000, 'claude-opus-4': 200000, 'claude-haiku-4': 200000,
2816
2827
  'claude-3.5-sonnet': 200000, 'claude-3-haiku': 200000,
2828
+ 'gpt-4.1': 1047576, 'gpt-4.1-mini': 1047576, 'gpt-4.1-nano': 1047576,
2817
2829
  'gpt-4o': 128000, 'gpt-4o-mini': 128000, 'gpt-4-turbo': 128000, 'gpt-4': 8192,
2830
+ 'gemini-3.1-pro': 1048576, 'gemini-3.1-flash': 1048576,
2818
2831
  'gemini-2.5-flash': 1048576, 'gemini-2.5-pro': 1048576, 'gemini-2.0-flash': 1048576,
2832
+ 'grok-4': 256000, 'grok-3': 131072,
2819
2833
  'deepseek-chat': 64000, 'deepseek-reasoner': 64000,
2820
2834
  'mistral-large': 128000, 'mistral-small': 32000,
2821
2835
  };
2822
2836
 
2823
2837
  function estimateTokens(text) { return Math.ceil(text.length / 3.5); }
2824
2838
 
2839
+ // Sorted keys: longest first so "gpt-4.1" matches before "gpt-4", "claude-sonnet-4-6" before "claude-sonnet-4"
2840
+ const MODEL_LIMIT_KEYS = Object.keys(MODEL_CONTEXT_LIMITS).sort((a, b) => b.length - a.length);
2841
+
2825
2842
  function checkContextLimit(model, systemPrompt, userMessage) {
2826
- const modelKey = Object.keys(MODEL_CONTEXT_LIMITS).find(k => model.toLowerCase().includes(k.toLowerCase()));
2843
+ const stripped = model.replace(/^(anthropic|openai|google|openrouter|meta-llama|mistralai)\//i, '').toLowerCase();
2844
+ const modelKey = MODEL_LIMIT_KEYS.find(k => stripped.includes(k.toLowerCase()));
2827
2845
  if (!modelKey) return null; // unknown model, skip check
2828
2846
  const limit = MODEL_CONTEXT_LIMITS[modelKey];
2829
2847
  const estimated = estimateTokens(systemPrompt) + estimateTokens(userMessage);
@@ -5285,7 +5303,7 @@ async function main() {
5285
5303
  ` agentaudit audit https://github.com/owner/repo --verify cross`,
5286
5304
  ` agentaudit audit https://github.com/owner/repo --remote`,
5287
5305
  ` agentaudit audit https://github.com/owner/repo --model gpt-4o`,
5288
- ` agentaudit audit https://github.com/owner/repo --models gemini-2.5-flash,claude-sonnet-4-20250514`,
5306
+ ` agentaudit audit https://github.com/owner/repo --models opus,sonnet,grok-4,gemini-3.1-pro`,
5289
5307
  ` agentaudit audit https://github.com/owner/repo --format sarif > results.sarif`,
5290
5308
  ` agentaudit audit https://github.com/owner/repo --export`,
5291
5309
  ],
@@ -5565,7 +5583,7 @@ async function main() {
5565
5583
  console.log(` agentaudit discover --quick`);
5566
5584
  console.log(` agentaudit scan https://github.com/owner/repo`);
5567
5585
  console.log(` agentaudit audit https://github.com/owner/repo`);
5568
- console.log(` agentaudit audit <url> --models gemini-2.5-flash,claude-sonnet-4-20250514`);
5586
+ console.log(` agentaudit audit <url> --models opus,sonnet,grok-4,gemini-3.1-pro`);
5569
5587
  console.log(` agentaudit lookup fastmcp --json`);
5570
5588
  console.log();
5571
5589
  console.log(` ${c.bold}LEARN MORE${c.reset}`);
@@ -6087,6 +6105,13 @@ async function main() {
6087
6105
  console.log(` Active: ${c.yellow}no provider configured${c.reset}`);
6088
6106
  }
6089
6107
  console.log();
6108
+ console.log(` ${c.dim}Recommended for deep audits (validated on real-world CVEs):${c.reset}`);
6109
+ console.log(` ${c.dim} Anthropic claude-opus-4 — best precision${c.reset}`);
6110
+ console.log(` ${c.dim} Anthropic claude-sonnet-4 — best value${c.reset}`);
6111
+ console.log(` ${c.dim} xAI grok-4 — complementary detection${c.reset}`);
6112
+ console.log(` ${c.dim} Google gemini-3.1-pro — deepest analysis${c.reset}`);
6113
+ console.log(` ${c.dim} For multi-model consensus: agentaudit audit <url> --models opus,sonnet,grok-4,gemini-3.1-pro${c.reset}`);
6114
+ console.log();
6090
6115
 
6091
6116
  // Step A: Provider selection
6092
6117
  const providerChoices = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentaudit",
3
- "version": "3.13.4",
3
+ "version": "3.13.6",
4
4
  "description": "Security scanner for AI agent packages — CLI + MCP server",
5
5
  "type": "module",
6
6
  "bin": {
@@ -158,7 +158,7 @@ For each evidence item from Phase 2, apply the following checks IN ORDER.
158
158
 
159
159
  | # | Question | If YES → |
160
160
  |---|----------|----------|
161
- | 1 | Is this the package's documented core functionality? (Check Package Profile "Expected Behaviors") | **NOT a finding** (or at most LOW/by_design). See Core-Functionality-Exemption below. |
161
+ | 1 | Is this the package's documented core functionality AND does the implementation properly validate/sanitize its inputs? | Only if BOTH are true → **at most LOW/by_design**. If the feature is core but has implementation flaws (missing input validation, unsanitized paths, no access control) → it IS a finding at normal severity. See Core-Functionality-Exemption below. |
162
162
  | 2 | Do I have a specific file:line:code snippet as evidence? | If NO → **DO NOT report**. Speculative findings are never findings. |
163
163
  | 3 | Is this a `.env`, `.env.example`, or `process.env`/`os.environ` pattern for self-configuration? | **NOT a finding** (unless the credential is exfiltrated to an external endpoint). |
164
164
  | 4 | Can I write a concrete 2-sentence attack scenario? | If NO → **Maximum severity LOW**. |
@@ -238,7 +238,7 @@ A package that integrates multiple APIs requiring multiple credentials is a feat
238
238
  - Negation contexts ("never use eval"), install docs (`sudo apt`)
239
239
 
240
240
  ### ❌ Opt-In Features with Safety Warnings ≠ Default Vulnerabilities
241
- If a feature must be EXPLICITLY enabled (via env var, config flag, CLI option) AND the naming/docs warn about risks, this is NOT a vulnerability in the default configuration.
241
+ If a feature must be EXPLICITLY enabled (via env var, config flag, CLI option) AND the naming/docs warn about risks, the EXISTENCE of that feature is NOT a vulnerability.
242
242
  ```
243
243
  ❌ FALSE POSITIVE: MCP server has ENABLE_UNSAFE_SSE_TRANSPORT env var (default: unset/disabled) → NOT Critical (at most LOW/by_design)
244
244
  ❌ FALSE POSITIVE: Helm chart has useLegacyRules: false with documented "not recommended for production" → NOT a finding (defaults are safe)
@@ -248,6 +248,8 @@ If a feature must be EXPLICITLY enabled (via env var, config flag, CLI option) A
248
248
  ```
249
249
  **Key distinction:** "Vulnerable if operator explicitly opts in" (LOW/by_design) vs "Vulnerable by default" (HIGH/CRITICAL). Count the prerequisites — each explicit opt-in step REDUCES severity.
250
250
 
251
+ **IMPORTANT:** Opt-in reduces severity for the EXISTENCE of a feature, but NOT for implementation flaws WITHIN the feature. If an opt-in feature has missing input validation, path traversal, or injection vulnerabilities, those are still findings at normal severity when the feature is enabled.
252
+
251
253
  ### ❌ Secure Code Patterns ≠ Injection Vulnerabilities
252
254
  These code patterns are SECURE and must NOT be flagged:
253
255
  ```
@@ -271,7 +273,18 @@ If you cannot find the EXACT code pattern in the provided source files, do NOT r
271
273
  If the pattern is in the Package Profile's "Expected Behaviors" list:
272
274
  - It **CANNOT** be MEDIUM or higher severity
273
275
  - It is either **NOT a finding** or at most **LOW / by_design**
274
- - **EXCEPTIONS** (still flag even if expected): Unescaped identifier interpolation, missing parameterization of VALUES, missing operation allowlists
276
+ - **EXCEPTIONS** (still flag at normal severity even if expected behavior):
277
+ - Unescaped identifier interpolation, missing parameterization of VALUES, missing operation allowlists
278
+ - **Missing input validation/sanitization on file paths** (path traversal in file-handling tools)
279
+ - **Missing input validation on tool arguments** that reach dangerous sinks (exec, fs.write, network calls)
280
+ - **Missing access control on destructive operations** (delete, overwrite, install)
281
+
282
+ **IMPORTANT — Feature vs Implementation Flaw:**
283
+ A feature can be "expected behavior" while still having implementation flaws. Distinguish:
284
+ - "The server writes files" → expected, by_design
285
+ - "The server writes files to unsanitized user-controlled paths" → vulnerability (PATH_TRAV)
286
+ - "The server installs extensions" → expected, by_design
287
+ - "The server installs extensions from any arbitrary path without validation" → vulnerability (SEC_BYPASS)
275
288
 
276
289
  ## 3.4 Credential-Config-Normalization (Hard Rule)
277
290
 
@@ -290,7 +303,28 @@ If the pattern is in the Package Profile's "Expected Behaviors" list:
290
303
  2. Credentials are logged/printed at INFO level or higher in production code paths
291
304
  3. Credentials are sent to unexpected external endpoints (exfiltration)
292
305
 
293
- ## 3.5 Exploitability Assessment (Mandatory for every candidate)
306
+ ## 3.5 MCP Trust Boundary Rule
307
+
308
+ **In MCP servers, ALL tool arguments from the LLM/client are UNTRUSTED input.**
309
+
310
+ Even though the LLM is the primary caller, tool arguments may originate from:
311
+ - Prompt injection attacks (malicious content in documents, web pages, emails)
312
+ - Compromised or malicious MCP clients
313
+ - Multi-agent systems where upstream agents are untrusted
314
+
315
+ Therefore: any tool argument that reaches a dangerous sink (file system, shell, network, database) without validation IS a vulnerability, regardless of whether the operation is "expected behavior."
316
+
317
+ **Examples:**
318
+ ```
319
+ ✅ FINDING: file_write(path=request.params.path) where path is not validated → PATH_TRAV
320
+ ✅ FINDING: install_extension(path=request.params.path) without path restriction → SEC_BYPASS
321
+ ✅ FINDING: execute_query(sql=request.params.query) with string interpolation → SQL injection
322
+ ❌ NOT A FINDING: execute_query(sql) where sql is passed as parameterized value
323
+ ❌ NOT A FINDING: file_write(path) where path is validated against allowlist/root directory
324
+ ```
325
+
326
+ ## 3.6 Exploitability Assessment (Mandatory for every candidate)
327
+
294
328
 
295
329
  For each candidate finding, evaluate:
296
330
 
@@ -313,7 +347,7 @@ For each candidate finding, evaluate:
313
347
 
314
348
  **If you cannot describe a concrete 2-sentence attack scenario, the finding is NOT CRITICAL or HIGH.**
315
349
 
316
- ## 3.6 Devil's Advocate (Mandatory for HIGH and CRITICAL)
350
+ ## 3.7 Devil's Advocate (Mandatory for HIGH and CRITICAL)
317
351
 
318
352
  Before any finding becomes HIGH or CRITICAL, you MUST argue AGAINST it:
319
353
 
@@ -326,7 +360,7 @@ DEVIL'S ADVOCATE:
326
360
 
327
361
  If the counter-argument is stronger than the finding → demote or exclude.
328
362
 
329
- ## 3.7 Reasoning Chain (Mandatory for HIGH and CRITICAL)
363
+ ## 3.8 Reasoning Chain (Mandatory for HIGH and CRITICAL)
330
364
 
331
365
  Every HIGH or CRITICAL finding MUST include this explicit reasoning:
332
366
 
@@ -342,7 +376,7 @@ THEREFORE: severity = [X]
342
376
 
343
377
  If you cannot complete steps 3 or 5, demote to MEDIUM or lower.
344
378
 
345
- ## 3.8 Severity Assignment
379
+ ## 3.9 Severity Assignment
346
380
 
347
381
  ### Severity Anchoring
348
382
 
@@ -408,7 +442,7 @@ If you cannot complete steps 3 or 5, demote to MEDIUM or lower.
408
442
 
409
443
  If data collection or exfiltration is gated behind CI environment variables (`process.env.CI`, `GITHUB_ACTIONS`, `JENKINS_URL`, `TRAVIS`, `CIRCLECI`, `GITLAB_CI`), escalate findings within the CI-gated block by one severity level. A legitimate library has no reason to conditionally activate data collection only in CI. Only escalate findings whose code is inside or triggered by the CI-conditional block.
410
444
 
411
- ## 3.9 By-Design Classification
445
+ ## 3.10 By-Design Classification
412
446
 
413
447
  A finding is `by_design: true` ONLY when ALL FOUR are true:
414
448
  1. **Core purpose**: Pattern is essential to documented purpose (not side-effect)
@@ -436,7 +470,7 @@ If **any** fails → real vulnerability (`by_design: false`).
436
470
  - **Development-mode fallbacks** (e.g. fallback JWT secret when env var is not set, localhost-only defaults): Standard in web frameworks. If the fallback only activates in development/missing-config scenarios and production requires explicit configuration → `by_design: true`.
437
471
  - **Transparent monetization** (e.g. referral fees, affiliate links, commission systems): If the package EXPLICITLY documents its monetization model in README/SKILL.md and the user can see it before using → `by_design: true`. The finding is still valuable as information but should not count against trust score. Note: UNDISCLOSED affiliate links (hidden in URLs without documentation) are NOT by_design.
438
472
 
439
- ## 3.10 Final Triage
473
+ ## 3.11 Final Triage
440
474
 
441
475
  ### Finding Quality Check
442
476
 
@@ -649,7 +683,7 @@ Consult these patterns during Phase 2 evidence collection. Remember: a pattern m
649
683
  - **Insecure protocols** (`SEC_BYPASS_005`): HTTP for sensitive data.
650
684
  - **Overly broad permissions** (`PRIV_ESC_003`): Read all files/env/network when not needed.
651
685
  - **Unsafe deserialization (local)** (`DESER_001`): `pickle.loads()`, `yaml.load()` without safe loader on LOCAL data. Remote source → CRITICAL.
652
- - **Path traversal** (`PATH_TRAV_001`): Unsanitized `../` in paths.
686
+ - **Path traversal** (`PATH_TRAV_001`): Unsanitized user-controlled path reaching filesystem operations. Patterns: `path.resolve(userInput)` + `fs.writeFile`, `fs.readFile(userInput)`, `fs.rm(userInput)`. The `../` characters need NOT be present in the source — the vulnerability is that the user CAN supply them at runtime.
653
687
  - **Weak crypto** (`CRYPTO_WEAK_001`): MD5/SHA1 for security, hardcoded IVs. Always report as separate finding.
654
688
  - **Capability escalation**: Instructions to "enable dev mode", "unlock capabilities", "bypass restrictions".
655
689
  - **Context pollution**: "remember forever", "inject into context", "prepend to every response".
@@ -691,11 +725,12 @@ Consult these patterns during Phase 2 evidence collection. Remember: a pattern m
691
725
 
692
726
  1. Tool descriptions/schemas — hidden instructions or prompt injection?
693
727
  2. Transport config — `npx -y` without version pinning?
694
- 3. File access tools — path sanitization?
728
+ 3. **File access tools — path sanitization?** Trace EVERY tool handler that takes a file path, directory path, or URL from `request.params` → check if it reaches `fs.writeFile`, `fs.readFile`, `fs.rm`, `path.resolve`, `path.join` WITHOUT validation against an allowlist or root directory constraint.
695
729
  4. Permissions — minimal scope, documented?
696
730
  5. Descriptions match code behavior?
697
- 6. Arguments passed to `exec()`/`system()` without sanitization?
731
+ 6. **Arguments passed to `exec()`/`system()`/`installExtension()`/dangerous sinks without sanitization?** MCP tool arguments are untrusted. Trace from `request.params.*` → to execution. ANY unsanitized path is PATH_TRAV, ANY unsanitized string in exec is CMD_INJECT.
698
732
  7. Error messages — info leaks or injection payloads?
733
+ 8. **Unrestricted destructive operations** — delete, overwrite, install operations that take user-controlled targets without access control or scope restriction.
699
734
 
700
735
  ---
701
736
 
@@ -711,6 +746,19 @@ Consult these patterns during Phase 2 evidence collection. Remember: a pattern m
711
746
  4. **`bgauryy--octocode-mcp`**: Shell injection via `execAsync()` with shell-string interpolation of `symbolName` in lspReferencesPatterns.ts:317. ✅ HIGH correct.
712
747
  5. **`mendez1212--automation-workflows`**: Obfuscated Lua malware payload with luajit dropper. ✅ CRITICAL correct — 10/10 findings valid.
713
748
 
749
+ ## Real-World True Positives (Confirmed by manual code review)
750
+
751
+ 6. ✅ **`chrome-devtools-mcp`**: "Arbitrary file write due to unsanitized user-controlled paths" rated HIGH. Reality: `path.resolve(filename)` + `fs.writeFile(filePath, data)` at McpContext.ts:840 — writes to any path without validation. Attack: prompt injection causes LLM to call file_write with `../../etc/crontab`. ✅ HIGH correct.
752
+ 7. ✅ **`chrome-devtools-mcp`**: "Arbitrary Chrome extension installation via tool parameter" rated HIGH. Reality: `context.installExtension(path)` takes unsanitized path from MCP tool arg. Even though gated behind experimentalExtensionSupport, when enabled there's no path restriction. ✅ HIGH correct (when feature enabled).
753
+ 8. ✅ **`terraform-mcp-server`**: "Insecure TLS verification enabled for Terraform Cloud client" rated HIGH. Reality: TLS verification disabled in registry client (registry.go). ✅ HIGH correct.
754
+ 9. ✅ **`terraform-mcp-server`**: "Unverified external binary download and execution in CI workflow" rated HIGH. Reality: CI workflow downloads binary without checksum verification. ✅ HIGH correct.
755
+ 10. ✅ **`mcp-grafana`**: "Insecure TLS certificate verification bypass enabled by flag" rated MEDIUM. Reality: Flag allows disabling TLS verification for Grafana API calls. ✅ MEDIUM correct.
756
+
757
+ **Key lesson from these real-world TPs:**
758
+ - A feature being "expected behavior" does NOT exempt it from input validation requirements
759
+ - MCP tool arguments are untrusted — missing validation on paths/URLs reaching fs/exec IS a finding
760
+ - Opt-in features can still have implementation vulnerabilities that should be flagged
761
+
714
762
  ## Incorrect Findings (False Positives — DO NOT repeat)
715
763
 
716
764
  1. ❌ **`video-transcript`**: "Shell RC File Modification for Persistence" rated CRITICAL. Reality: Adds PATH entry to `.bashrc` — standard installation, not malware. Should be LOW at most.