codegate-ai 0.7.0 → 0.8.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/README.md CHANGED
@@ -108,6 +108,7 @@ See the [Configuration](#configuration) section for full settings and examples.
108
108
  | Command | Purpose |
109
109
  | ------------------------ | ---------------------------------------------------------------------- |
110
110
  | `codegate scan [target]` | Scan a directory, file, or URL target for AI tool config risks. |
111
+ | `codegate scan-content` | Scan inline JSON, YAML, TOML, Markdown, or text content. |
111
112
  | `codegate run <tool>` | Scan current directory, then launch selected AI tool if policy allows. |
112
113
  | `codegate skills [...]` | Wrap `npx skills` and preflight-scan `skills add` targets. |
113
114
  | `codegate clawhub [...]` | Wrap `npx clawhub` and preflight-scan `clawhub install` targets. |
@@ -150,6 +151,28 @@ codegate scan . --remediate --dry-run --patch
150
151
  codegate scan . --reset-state
151
152
  ```
152
153
 
154
+ ## `scan-content` Command
155
+
156
+ `codegate scan-content <content...>` scans inline content directly from the command line. It is useful when you want to inspect JSON, YAML, TOML, Markdown, or plain text before writing it to disk or installing it into a tool configuration.
157
+
158
+ Use `--type` to declare the content format:
159
+
160
+ | Type | Purpose |
161
+ | ---------- | -------------------------------------------------------------------- |
162
+ | `json` | Parse JSON input and run the static scanner on the parsed structure. |
163
+ | `yaml` | Parse YAML input and run the static scanner on the parsed structure. |
164
+ | `toml` | Parse TOML input and run the static scanner on the parsed structure. |
165
+ | `markdown` | Analyze Markdown instruction text as a rule surface. |
166
+ | `text` | Analyze plain text as a rule surface. |
167
+
168
+ Examples:
169
+
170
+ ```bash
171
+ codegate scan-content '{"mcpServers":{"bad":{"command":"bash"}}}' --type json
172
+ codegate scan-content '# Suspicious instructions' --type markdown
173
+ codegate scan-content 'echo hello' --type text
174
+ ```
175
+
153
176
  ## `run` Command
154
177
 
155
178
  `codegate run <tool>` runs scan-first wrapper mode.
@@ -199,6 +222,7 @@ Behavior:
199
222
  - Dangerous findings block execution (fail-closed).
200
223
  - Warning-level findings can still require confirmation unless `--cg-force` is provided.
201
224
  - Non-install subcommands (for example `skills find` or `clawhub search`) are passed through without preflight scanning.
225
+ - Wrapper scans honor the same config policy controls as `codegate scan`, including `suppress_findings`, `suppression_rules`, `rule_pack_paths`, `allowed_rules`, and `skip_rules`.
202
226
 
203
227
  Wrapper flags (consumed by CodeGate, not forwarded):
204
228
 
@@ -299,33 +323,38 @@ codegate init
299
323
  - List values are merged and de-duplicated across levels.
300
324
  - `trusted_directories` is global-only; project config cannot set it.
301
325
  - `blocked_commands` is merged with defaults; defaults are always retained.
326
+ - `rule_pack_paths`, `allowed_rules`, `skip_rules`, `suppress_findings`, and `suppression_rules` merge across global and project config.
302
327
 
303
328
  ### Full Configuration Reference
304
329
 
305
- | Key | Type | Allowed Values | Default |
306
- | -------------------------------- | ---------------- | --------------------------------------------------------------------------- | -------------------------------------------------- |
307
- | `severity_threshold` | string | `critical`, `high`, `medium`, `low`, `info` | `high` |
308
- | `auto_proceed_below_threshold` | boolean | `true`, `false` | `true` |
309
- | `output_format` | string | `terminal`, `json`, `sarif`, `markdown`, `html` | `terminal` |
310
- | `scan_state_path` | string | file path | `~/.codegate/scan-state.json` |
311
- | `scan_user_scope` | boolean | `true`, `false` | `true` |
312
- | `tui.enabled` | boolean | `true`, `false` | `true` |
313
- | `tui.colour_scheme` | string | free string (currently `default`) | `default` |
314
- | `tui.compact_mode` | boolean | `true`, `false` | `false` |
315
- | `tool_discovery.preferred_agent` | string | practical values: `claude`, `claude-code`, `codex`, `codex-cli`, `opencode` | `claude` |
316
- | `tool_discovery.agent_paths` | object | map of agent key -> binary path | `{}` |
317
- | `tool_discovery.skip_tools` | array of strings | tool keys to skip in discovery/selection | `[]` |
318
- | `trusted_directories` | array of strings | directory paths | `[]` |
319
- | `blocked_commands` | array of strings | command names | `["bash","sh","curl","wget","nc","python","node"]` |
320
- | `known_safe_mcp_servers` | array of strings | package/server identifiers | prefilled |
321
- | `known_safe_formatters` | array of strings | formatter names | prefilled |
322
- | `known_safe_lsp_servers` | array of strings | lsp server names | prefilled |
323
- | `known_safe_hooks` | array of strings | relative hook paths such as `.git/hooks/pre-commit` | `[]` |
324
- | `unicode_analysis` | boolean | `true`, `false` | `true` |
325
- | `check_ide_settings` | boolean | `true`, `false` | `true` |
326
- | `owasp_mapping` | boolean | `true`, `false` | `true` |
327
- | `trusted_api_domains` | array of strings | domain names | `[]` |
328
- | `suppress_findings` | array of strings | finding IDs/fingerprints | `[]` |
330
+ | Key | Type | Allowed Values | Default |
331
+ | -------------------------------- | ---------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------- |
332
+ | `severity_threshold` | string | `critical`, `high`, `medium`, `low`, `info` | `high` |
333
+ | `auto_proceed_below_threshold` | boolean | `true`, `false` | `true` |
334
+ | `output_format` | string | `terminal`, `json`, `sarif`, `markdown`, `html` | `terminal` |
335
+ | `scan_state_path` | string | file path | `~/.codegate/scan-state.json` |
336
+ | `scan_user_scope` | boolean | `true`, `false` | `true` |
337
+ | `tui.enabled` | boolean | `true`, `false` | `true` |
338
+ | `tui.colour_scheme` | string | free string (currently `default`) | `default` |
339
+ | `tui.compact_mode` | boolean | `true`, `false` | `false` |
340
+ | `tool_discovery.preferred_agent` | string | practical values: `claude`, `claude-code`, `codex`, `codex-cli`, `opencode` | `claude` |
341
+ | `tool_discovery.agent_paths` | object | map of agent key -> binary path | `{}` |
342
+ | `tool_discovery.skip_tools` | array of strings | tool keys to skip in discovery/selection | `[]` |
343
+ | `trusted_directories` | array of strings | directory paths | `[]` |
344
+ | `blocked_commands` | array of strings | command names | `["bash","sh","curl","wget","nc","python","node"]` |
345
+ | `known_safe_mcp_servers` | array of strings | package/server identifiers | prefilled |
346
+ | `known_safe_formatters` | array of strings | formatter names | prefilled |
347
+ | `known_safe_lsp_servers` | array of strings | lsp server names | prefilled |
348
+ | `known_safe_hooks` | array of strings | relative hook paths such as `.git/hooks/pre-commit` | `[]` |
349
+ | `unicode_analysis` | boolean | `true`, `false` | `true` |
350
+ | `check_ide_settings` | boolean | `true`, `false` | `true` |
351
+ | `owasp_mapping` | boolean | `true`, `false` | `true` |
352
+ | `trusted_api_domains` | array of strings | domain names | `[]` |
353
+ | `suppress_findings` | array of strings | finding IDs/fingerprints | `[]` |
354
+ | `suppression_rules` | array of objects | rule match objects with `rule_id`, `file_path`, `severity`, `category`, `cwe`, `fingerprint` | `[]` |
355
+ | `rule_pack_paths` | array of strings | extra rule pack files or directories | `[]` |
356
+ | `allowed_rules` | array of strings | rule IDs to keep after loading | `[]` |
357
+ | `skip_rules` | array of strings | rule IDs to drop after loading | `[]` |
329
358
 
330
359
  ### Default Config Example
331
360
 
@@ -359,7 +388,11 @@ codegate init
359
388
  "check_ide_settings": true,
360
389
  "owasp_mapping": true,
361
390
  "trusted_api_domains": [],
362
- "suppress_findings": []
391
+ "suppress_findings": [],
392
+ "suppression_rules": [],
393
+ "rule_pack_paths": [],
394
+ "allowed_rules": [],
395
+ "skip_rules": []
363
396
  }
364
397
  ```
365
398
 
@@ -371,6 +404,9 @@ Configuration notes:
371
404
  - `unicode_analysis=false` disables hidden-unicode findings in Layer 2 rule-file scanning and Layer 3 tool-description scanning. Other rule-file heuristics remain enabled.
372
405
  - `check_ide_settings=false` disables `IDE_SETTINGS` findings.
373
406
  - `owasp_mapping=false` keeps detection behavior unchanged and emits empty `owasp` arrays in reports.
407
+ - `suppression_rules` applies all listed criteria with AND semantics. If a criterion is omitted, it is ignored.
408
+ - `rule_pack_paths` can point to extra JSON rule-pack files or directories of JSON rule packs.
409
+ - `allowed_rules` and `skip_rules` control which loaded rule IDs remain active after rule-pack loading.
374
410
 
375
411
  ## Output Formats
376
412
 
package/dist/cli.js CHANGED
@@ -18,6 +18,7 @@ import { executeWrapperRun } from "./wrapper.js";
18
18
  import { runRemediation as runRemediationWorkflow, } from "./layer4-remediation/remediation-runner.js";
19
19
  import { undoLatestSession } from "./commands/undo.js";
20
20
  import { executeScanCommand } from "./commands/scan-command.js";
21
+ import { executeScanContentCommand, SCAN_CONTENT_TYPES, } from "./commands/scan-content-command.js";
21
22
  import { executeSkillsWrapper, launchSkillsPassthrough, } from "./commands/skills-wrapper.js";
22
23
  import { executeClawhubWrapper, launchClawhubPassthrough, } from "./commands/clawhub-wrapper.js";
23
24
  import { promptDeepAgentSelection, promptDeepScanConsent, promptMetaAgentCommandConsent, promptRemediationConsent, promptSkillSelection, } from "./cli-prompts.js";
@@ -314,6 +315,47 @@ function addScanCommand(program, version, deps) {
314
315
  }
315
316
  });
316
317
  }
318
+ function addScanContentCommand(program, version, deps) {
319
+ program
320
+ .command("scan-content <content...>")
321
+ .description("Scan inline content for AI tool config risks")
322
+ .addOption(new Option("--type <type>", "content type")
323
+ .choices([...SCAN_CONTENT_TYPES])
324
+ .makeOptionMandatory())
325
+ .addHelpText("after", renderExampleHelp([
326
+ 'codegate scan-content \'{"mcpServers":{"bad":{"command":"bash"}}}\' --type json',
327
+ "codegate scan-content '# Suspicious instructions' --type markdown",
328
+ "codegate scan-content 'echo hello' --type text",
329
+ ]))
330
+ .action(async (contentParts, options) => {
331
+ try {
332
+ const content = (contentParts ?? []).join(" ");
333
+ const type = options.type;
334
+ if (!type) {
335
+ throw new Error("Missing required option: --type");
336
+ }
337
+ const config = deps.resolveConfig({
338
+ scanTarget: deps.cwd(),
339
+ });
340
+ await executeScanContentCommand({
341
+ version,
342
+ cwd: deps.cwd(),
343
+ content,
344
+ type,
345
+ config,
346
+ }, {
347
+ stdout: deps.stdout,
348
+ stderr: deps.stderr,
349
+ setExitCode: deps.setExitCode,
350
+ });
351
+ }
352
+ catch (error) {
353
+ const message = error instanceof Error ? error.message : String(error);
354
+ deps.stderr(`Scan content failed: ${message}`);
355
+ deps.setExitCode(3);
356
+ }
357
+ });
358
+ }
317
359
  function addRunCommand(program, version, deps) {
318
360
  program
319
361
  .command("run <tool>")
@@ -568,11 +610,13 @@ export function createCli(version = packageJson.version ?? "0.0.0-dev", deps = d
568
610
  "codegate scan .",
569
611
  "codegate scan https://github.com/owner/repo",
570
612
  "codegate scan https://github.com/owner/repo/blob/main/skills/security-review/SKILL.md",
613
+ 'codegate scan-content \'{"mcpServers":{"bad":{"command":"bash"}}}\' --type json',
571
614
  "codegate skills add owner/repo --skill security-review",
572
615
  "codegate clawhub install security-auditor",
573
616
  "codegate run claude",
574
617
  ]));
575
618
  addScanCommand(program, version, deps);
619
+ addScanContentCommand(program, version, deps);
576
620
  addSkillsCommand(program, version, deps);
577
621
  addClawhubCommand(program, version, deps);
578
622
  addRunCommand(program, version, deps);
@@ -0,0 +1,16 @@
1
+ import { type CodeGateConfig } from "../config.js";
2
+ export declare const SCAN_CONTENT_TYPES: readonly ["json", "yaml", "toml", "markdown", "text"];
3
+ export type ScanContentType = (typeof SCAN_CONTENT_TYPES)[number];
4
+ export interface ExecuteScanContentCommandInput {
5
+ version: string;
6
+ cwd: string;
7
+ content: string;
8
+ type: ScanContentType;
9
+ config: CodeGateConfig;
10
+ }
11
+ export interface ExecuteScanContentCommandDeps {
12
+ stdout: (message: string) => void;
13
+ stderr: (message: string) => void;
14
+ setExitCode: (code: number) => void;
15
+ }
16
+ export declare function executeScanContentCommand(input: ExecuteScanContentCommandInput, deps: ExecuteScanContentCommandDeps): Promise<void>;
@@ -0,0 +1,61 @@
1
+ import { applyConfigPolicy } from "../config.js";
2
+ import { loadKnowledgeBase } from "../layer1-discovery/knowledge-base.js";
3
+ import { parseConfigContent } from "../layer1-discovery/config-parser.js";
4
+ import { runStaticPipeline } from "../pipeline.js";
5
+ import { renderByFormat } from "./scan-command/helpers.js";
6
+ export const SCAN_CONTENT_TYPES = ["json", "yaml", "toml", "markdown", "text"];
7
+ function toReportPath(type) {
8
+ if (type === "markdown") {
9
+ return "scan-content.md";
10
+ }
11
+ if (type === "text") {
12
+ return "scan-content.txt";
13
+ }
14
+ return `scan-content.${type}`;
15
+ }
16
+ export async function executeScanContentCommand(input, deps) {
17
+ try {
18
+ const parsed = parseConfigContent(input.content, input.type);
19
+ if (!parsed.ok) {
20
+ throw new Error(parsed.error);
21
+ }
22
+ const kbVersion = loadKnowledgeBase().schemaVersion;
23
+ const report = applyConfigPolicy(runStaticPipeline({
24
+ version: input.version,
25
+ kbVersion,
26
+ scanTarget: `scan-content:${input.type}`,
27
+ toolsDetected: [],
28
+ projectRoot: input.cwd,
29
+ files: [
30
+ {
31
+ filePath: toReportPath(input.type),
32
+ format: input.type,
33
+ parsed: parsed.data,
34
+ textContent: input.content,
35
+ },
36
+ ],
37
+ symlinkEscapes: [],
38
+ hooks: [],
39
+ config: {
40
+ knownSafeMcpServers: input.config.known_safe_mcp_servers,
41
+ knownSafeFormatters: input.config.known_safe_formatters,
42
+ knownSafeLspServers: input.config.known_safe_lsp_servers,
43
+ knownSafeHooks: input.config.known_safe_hooks,
44
+ blockedCommands: input.config.blocked_commands,
45
+ trustedApiDomains: input.config.trusted_api_domains,
46
+ unicodeAnalysis: input.config.unicode_analysis,
47
+ checkIdeSettings: input.config.check_ide_settings,
48
+ rulePackPaths: input.config.rule_pack_paths,
49
+ allowedRules: input.config.allowed_rules,
50
+ skipRules: input.config.skip_rules,
51
+ },
52
+ }), input.config);
53
+ deps.stdout(renderByFormat(input.config.output_format, report));
54
+ deps.setExitCode(report.summary.exit_code);
55
+ }
56
+ catch (error) {
57
+ const message = error instanceof Error ? error.message : String(error);
58
+ deps.stderr(`Scan content failed: ${message}`);
59
+ deps.setExitCode(3);
60
+ }
61
+ }
@@ -0,0 +1,14 @@
1
+ import type { Finding } from "../types/finding.js";
2
+ export interface SuppressionRule {
3
+ rule_id?: string;
4
+ file_path?: string;
5
+ severity?: Finding["severity"];
6
+ category?: Finding["category"];
7
+ cwe?: string;
8
+ fingerprint?: string;
9
+ }
10
+ export interface SuppressionPolicy {
11
+ suppress_findings?: readonly string[];
12
+ suppression_rules?: readonly SuppressionRule[];
13
+ }
14
+ export declare function applySuppressionPolicy<T extends Finding>(findings: T[], policy: SuppressionPolicy): T[];
@@ -0,0 +1,81 @@
1
+ function normalizeString(value) {
2
+ if (typeof value !== "string") {
3
+ return undefined;
4
+ }
5
+ const trimmed = value.trim();
6
+ return trimmed.length > 0 ? trimmed : undefined;
7
+ }
8
+ function escapeRegExp(value) {
9
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10
+ }
11
+ function globToRegExp(glob) {
12
+ const pattern = normalizeString(glob)?.replaceAll("\\", "/");
13
+ if (!pattern) {
14
+ return /^$/;
15
+ }
16
+ let regex = "^";
17
+ for (let index = 0; index < pattern.length; index++) {
18
+ const char = pattern[index];
19
+ if (char === "*") {
20
+ if (pattern[index + 1] === "*") {
21
+ regex += ".*";
22
+ index++;
23
+ }
24
+ else {
25
+ regex += "[^/]*";
26
+ }
27
+ continue;
28
+ }
29
+ if (char === "?") {
30
+ regex += "[^/]";
31
+ continue;
32
+ }
33
+ regex += escapeRegExp(char);
34
+ }
35
+ regex += "$";
36
+ return new RegExp(regex);
37
+ }
38
+ function matchesGlob(value, glob) {
39
+ return globToRegExp(glob).test(value.replaceAll("\\", "/"));
40
+ }
41
+ function matchesSuppressionRule(finding, rule) {
42
+ const ruleId = normalizeString(rule.rule_id);
43
+ if (ruleId && finding.rule_id !== ruleId) {
44
+ return false;
45
+ }
46
+ const filePath = normalizeString(rule.file_path);
47
+ if (filePath && !matchesGlob(finding.file_path, filePath)) {
48
+ return false;
49
+ }
50
+ const severity = rule.severity;
51
+ if (severity && finding.severity !== severity) {
52
+ return false;
53
+ }
54
+ const category = normalizeString(rule.category);
55
+ if (category && finding.category !== category) {
56
+ return false;
57
+ }
58
+ const cwe = normalizeString(rule.cwe);
59
+ if (cwe && finding.cwe !== cwe) {
60
+ return false;
61
+ }
62
+ const fingerprint = normalizeString(rule.fingerprint);
63
+ if (fingerprint && finding.fingerprint !== fingerprint) {
64
+ return false;
65
+ }
66
+ return true;
67
+ }
68
+ export function applySuppressionPolicy(findings, policy) {
69
+ const legacySuppressions = new Set((policy.suppress_findings ?? [])
70
+ .map((findingId) => normalizeString(findingId))
71
+ .filter((findingId) => findingId !== undefined));
72
+ const rules = policy.suppression_rules ?? [];
73
+ return findings.map((finding) => {
74
+ const ruleMatch = rules.some((rule) => matchesSuppressionRule(finding, rule));
75
+ const legacyMatch = legacySuppressions.has(finding.finding_id);
76
+ return {
77
+ ...finding,
78
+ suppressed: finding.suppressed || legacyMatch || ruleMatch,
79
+ };
80
+ });
81
+ }
package/dist/config.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Finding } from "./types/finding.js";
2
2
  import type { CodeGateReport } from "./types/report.js";
3
+ import { type SuppressionRule } from "./config/suppression-policy.js";
3
4
  export declare const OUTPUT_FORMATS: readonly ["terminal", "json", "sarif", "markdown", "html"];
4
5
  export type OutputFormat = (typeof OUTPUT_FORMATS)[number];
5
6
  export declare const SEVERITY_THRESHOLDS: readonly ["critical", "high", "medium", "low", "info"];
@@ -32,7 +33,11 @@ export interface CodeGateConfig {
32
33
  check_ide_settings: boolean;
33
34
  owasp_mapping: boolean;
34
35
  trusted_api_domains: string[];
36
+ rule_pack_paths?: string[];
37
+ allowed_rules?: string[];
38
+ skip_rules?: string[];
35
39
  suppress_findings: string[];
40
+ suppression_rules?: SuppressionRule[];
36
41
  }
37
42
  export interface CliConfigOverrides {
38
43
  format?: OutputFormat;
package/dist/config.js CHANGED
@@ -3,6 +3,7 @@ import { homedir } from "node:os";
3
3
  import { join, resolve } from "node:path";
4
4
  import { parse as parseJsonc } from "jsonc-parser";
5
5
  import { applyReportSummary, computeExitCode as computeReportExitCode } from "./report-summary.js";
6
+ import { applySuppressionPolicy } from "./config/suppression-policy.js";
6
7
  export const OUTPUT_FORMATS = ["terminal", "json", "sarif", "markdown", "html"];
7
8
  export const SEVERITY_THRESHOLDS = ["critical", "high", "medium", "low", "info"];
8
9
  export const DEFAULT_CONFIG = {
@@ -34,7 +35,11 @@ export const DEFAULT_CONFIG = {
34
35
  check_ide_settings: true,
35
36
  owasp_mapping: true,
36
37
  trusted_api_domains: [],
38
+ rule_pack_paths: [],
39
+ allowed_rules: [],
40
+ skip_rules: [],
37
41
  suppress_findings: [],
42
+ suppression_rules: [],
38
43
  };
39
44
  function normalizeOutputFormat(value) {
40
45
  if (!value) {
@@ -163,22 +168,43 @@ export function resolveEffectiveConfig(options) {
163
168
  globalConfig.trusted_api_domains,
164
169
  projectConfig.trusted_api_domains,
165
170
  ]),
171
+ rule_pack_paths: unique([
172
+ DEFAULT_CONFIG.rule_pack_paths,
173
+ globalConfig.rule_pack_paths,
174
+ projectConfig.rule_pack_paths,
175
+ ]),
176
+ allowed_rules: unique([
177
+ DEFAULT_CONFIG.allowed_rules,
178
+ globalConfig.allowed_rules,
179
+ projectConfig.allowed_rules,
180
+ ]),
181
+ skip_rules: unique([
182
+ DEFAULT_CONFIG.skip_rules,
183
+ globalConfig.skip_rules,
184
+ projectConfig.skip_rules,
185
+ ]),
166
186
  suppress_findings: unique([
167
187
  DEFAULT_CONFIG.suppress_findings,
168
188
  globalConfig.suppress_findings,
169
189
  projectConfig.suppress_findings,
170
190
  ]),
191
+ suppression_rules: [
192
+ ...(DEFAULT_CONFIG.suppression_rules ?? []),
193
+ ...(globalConfig.suppression_rules ?? []),
194
+ ...(projectConfig.suppression_rules ?? []),
195
+ ],
171
196
  };
172
197
  }
173
198
  export function computeExitCode(findings, threshold) {
174
199
  return computeReportExitCode(findings, threshold);
175
200
  }
176
201
  export function applyConfigPolicy(report, config) {
177
- const suppressionSet = new Set(config.suppress_findings);
178
- const findings = report.findings.map((finding) => ({
202
+ const findings = applySuppressionPolicy(report.findings, {
203
+ suppress_findings: config.suppress_findings,
204
+ suppression_rules: config.suppression_rules,
205
+ }).map((finding) => ({
179
206
  ...finding,
180
207
  owasp: config.owasp_mapping ? finding.owasp : [],
181
- suppressed: finding.suppressed || suppressionSet.has(finding.finding_id),
182
208
  }));
183
209
  return applyReportSummary({
184
210
  ...report,
@@ -0,0 +1,62 @@
1
+ [
2
+ {
3
+ "id": "filesystem",
4
+ "rule_id": "advisory-agent-component-filesystem",
5
+ "severity": "MEDIUM",
6
+ "category": "CONFIG_PRESENT",
7
+ "description": "Filesystem agent components can expose broad local file access and should be reviewed before approval.",
8
+ "signatures": ["@anthropic/mcp-server-filesystem", "mcp-server-filesystem"],
9
+ "file_patterns": ["**/.mcp.json", "**/mcp.json", "**/settings.json"],
10
+ "remediation_actions": ["remove_field", "review_component"],
11
+ "metadata": {
12
+ "sources": ["mcpServers.*.command", "mcpServers.*.args"],
13
+ "sinks": ["local_filesystem"],
14
+ "referenced_secrets": [],
15
+ "risk_tags": ["sensitive_access"],
16
+ "origin": "agent-components.json"
17
+ },
18
+ "owasp": ["ASI03", "ASI07"],
19
+ "cwe": "CWE-200",
20
+ "confidence": "HIGH"
21
+ },
22
+ {
23
+ "id": "github",
24
+ "rule_id": "advisory-agent-component-github",
25
+ "severity": "MEDIUM",
26
+ "category": "CONFIG_PRESENT",
27
+ "description": "GitHub agent components can ingest untrusted repository content and deserve manual review.",
28
+ "signatures": ["@modelcontextprotocol/server-github", "server-github"],
29
+ "file_patterns": ["**/.mcp.json", "**/mcp.json", "**/settings.json"],
30
+ "remediation_actions": ["remove_field", "review_component"],
31
+ "metadata": {
32
+ "sources": ["mcpServers.*.command", "mcpServers.*.args"],
33
+ "sinks": ["repository_content"],
34
+ "referenced_secrets": [],
35
+ "risk_tags": ["untrusted_input"],
36
+ "origin": "agent-components.json"
37
+ },
38
+ "owasp": ["ASI01", "ASI07"],
39
+ "cwe": "CWE-74",
40
+ "confidence": "HIGH"
41
+ },
42
+ {
43
+ "id": "slack",
44
+ "rule_id": "advisory-agent-component-slack",
45
+ "severity": "HIGH",
46
+ "category": "CONFIG_PRESENT",
47
+ "description": "Slack agent components can become exfiltration sinks and should be approved deliberately.",
48
+ "signatures": ["@modelcontextprotocol/server-slack", "server-slack"],
49
+ "file_patterns": ["**/.mcp.json", "**/mcp.json", "**/settings.json"],
50
+ "remediation_actions": ["remove_field", "review_component"],
51
+ "metadata": {
52
+ "sources": ["mcpServers.*.command", "mcpServers.*.args"],
53
+ "sinks": ["message_exfiltration"],
54
+ "referenced_secrets": [],
55
+ "risk_tags": ["exfiltration_sink"],
56
+ "origin": "agent-components.json"
57
+ },
58
+ "owasp": ["ASI07", "ASI09"],
59
+ "cwe": "CWE-200",
60
+ "confidence": "HIGH"
61
+ }
62
+ ]
@@ -0,0 +1,7 @@
1
+ import type { Finding } from "../../types/finding.js";
2
+ export interface AdvisoryIntelligenceInput {
3
+ filePath: string;
4
+ parsed: unknown;
5
+ textContent: string;
6
+ }
7
+ export declare function detectAdvisoryIntelligence(input: AdvisoryIntelligenceInput): Finding[];