security-mcp 1.0.5 → 1.1.1

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.
Files changed (81) hide show
  1. package/README.md +963 -193
  2. package/defaults/agent-run-schema.json +98 -0
  3. package/defaults/checklists/ai.json +25 -0
  4. package/defaults/checklists/api.json +27 -0
  5. package/defaults/checklists/infra.json +27 -0
  6. package/defaults/checklists/mobile.json +25 -0
  7. package/defaults/checklists/payments.json +25 -0
  8. package/defaults/checklists/web.json +30 -0
  9. package/defaults/control-catalog.json +392 -0
  10. package/defaults/evidence-map.json +194 -0
  11. package/defaults/security-policy.json +41 -2
  12. package/dist/cli/index.js +13 -8
  13. package/dist/cli/install.js +80 -2
  14. package/dist/cli/onboarding.js +590 -0
  15. package/dist/cli/update.js +83 -15
  16. package/dist/gate/baseline.js +115 -0
  17. package/dist/gate/checks/ai-redteam.js +398 -0
  18. package/dist/gate/checks/api.js +93 -0
  19. package/dist/gate/checks/crypto.js +153 -0
  20. package/dist/gate/checks/database.js +144 -0
  21. package/dist/gate/checks/dependencies.js +126 -0
  22. package/dist/gate/checks/dlp.js +153 -0
  23. package/dist/gate/checks/graphql.js +122 -0
  24. package/dist/gate/checks/infra.js +126 -12
  25. package/dist/gate/checks/k8s.js +190 -0
  26. package/dist/gate/checks/playbook.js +160 -0
  27. package/dist/gate/checks/runtime.js +316 -0
  28. package/dist/gate/checks/sbom.js +199 -0
  29. package/dist/gate/checks/scanners.js +379 -8
  30. package/dist/gate/checks/secrets.js +85 -20
  31. package/dist/gate/exceptions.js +6 -1
  32. package/dist/gate/policy.js +85 -19
  33. package/dist/gate/threat-intel.js +157 -0
  34. package/dist/mcp/orchestration.js +586 -0
  35. package/dist/mcp/server.js +568 -16
  36. package/dist/repo/search.js +11 -1
  37. package/dist/review/store.js +133 -0
  38. package/dist/types/agent-run.js +8 -0
  39. package/package.json +5 -5
  40. package/prompts/SECURITY_PROMPT.md +415 -1
  41. package/skills/agentic-loop-exploiter/SKILL.md +69 -0
  42. package/skills/ai-llm-redteam/SKILL.md +118 -0
  43. package/skills/algorithm-implementation-reviewer/SKILL.md +85 -0
  44. package/skills/android-penetration-tester/SKILL.md +83 -0
  45. package/skills/appsec-code-auditor/SKILL.md +86 -0
  46. package/skills/artifact-integrity-analyst/SKILL.md +68 -0
  47. package/skills/attack-navigator/SKILL.md +64 -0
  48. package/skills/auth-session-hacker/SKILL.md +87 -0
  49. package/skills/aws-penetration-tester/SKILL.md +60 -0
  50. package/skills/azure-penetration-tester/SKILL.md +64 -0
  51. package/skills/business-logic-attacker/SKILL.md +76 -0
  52. package/skills/cicd-pipeline-hijacker/SKILL.md +81 -0
  53. package/skills/ciso-orchestrator/SKILL.md +165 -0
  54. package/skills/cloud-infra-specialist/SKILL.md +85 -0
  55. package/skills/compliance-gap-analyst/SKILL.md +77 -0
  56. package/skills/compliance-grc/SKILL.md +148 -0
  57. package/skills/crypto-pki-specialist/SKILL.md +136 -0
  58. package/skills/dependency-confusion-attacker/SKILL.md +78 -0
  59. package/skills/evidence-collector/SKILL.md +86 -0
  60. package/skills/gcp-penetration-tester/SKILL.md +63 -0
  61. package/skills/injection-specialist/SKILL.md +62 -0
  62. package/skills/ios-security-auditor/SKILL.md +77 -0
  63. package/skills/k8s-container-escaper/SKILL.md +74 -0
  64. package/skills/key-management-lifecycle-analyst/SKILL.md +92 -0
  65. package/skills/logic-race-fuzzer/SKILL.md +67 -0
  66. package/skills/mobile-api-network-attacker/SKILL.md +81 -0
  67. package/skills/mobile-security-specialist/SKILL.md +124 -0
  68. package/skills/model-extraction-attacker/SKILL.md +68 -0
  69. package/skills/pentest-infra/SKILL.md +69 -0
  70. package/skills/pentest-social/SKILL.md +72 -0
  71. package/skills/pentest-team/SKILL.md +126 -0
  72. package/skills/pentest-web-api/SKILL.md +71 -0
  73. package/skills/privacy-flow-analyst/SKILL.md +70 -0
  74. package/skills/prompt-injection-specialist/SKILL.md +76 -0
  75. package/skills/rag-poisoning-specialist/SKILL.md +71 -0
  76. package/skills/senior-security-engineer/SKILL.md +75 -13
  77. package/skills/serialization-memory-attacker/SKILL.md +78 -0
  78. package/skills/stride-pasta-analyst/SKILL.md +72 -0
  79. package/skills/supply-chain-devsecops/SKILL.md +82 -0
  80. package/skills/threat-modeler/SKILL.md +116 -0
  81. package/skills/tls-certificate-auditor/SKILL.md +76 -0
package/dist/cli/index.js CHANGED
@@ -57,12 +57,14 @@ COMMANDS
57
57
  config Print MCP config JSON for manual editor setup
58
58
 
59
59
  OPTIONS (install)
60
- --claude-code Write config for Claude Code only
61
- --cursor Write config for Cursor only
62
- --vscode Write config for VS Code only
63
- --global Write to global editor config (default)
60
+ --claude-code Write config for Claude Code only
61
+ --cursor Write config for Cursor only
62
+ --vscode Write config for VS Code only
63
+ --global Write to global editor config (default)
64
64
  --use-global-binary Write configs that execute "security-mcp serve" instead of npx
65
- --dry-run Print what would change without writing
65
+ --dry-run Print what would change without writing
66
+ --yes Skip interactive setup questions (install with defaults)
67
+ --non-interactive Same as --yes (for CI environments)
66
68
 
67
69
  OPTIONS (general)
68
70
  --version Print version
@@ -131,26 +133,29 @@ async function main() {
131
133
  break;
132
134
  }
133
135
  case "install": {
136
+ const noEditorFlag = !args.includes("--claude-code") && !args.includes("--cursor") && !args.includes("--vscode");
134
137
  const options = {
135
138
  claudeCode: args.includes("--claude-code"),
136
139
  cursor: args.includes("--cursor"),
137
140
  vscode: args.includes("--vscode"),
138
141
  dryRun: args.includes("--dry-run"),
139
142
  useGlobalBinary,
140
- // If no editor flag specified, install to all detected
141
- all: !args.includes("--claude-code") && !args.includes("--cursor") && !args.includes("--vscode")
143
+ all: noEditorFlag,
144
+ interactive: !args.includes("--yes") && !args.includes("--non-interactive")
142
145
  };
143
146
  await runInstall(options);
144
147
  break;
145
148
  }
146
149
  case "install-global": {
150
+ const noEditorFlag = !args.includes("--claude-code") && !args.includes("--cursor") && !args.includes("--vscode");
147
151
  const options = {
148
152
  claudeCode: args.includes("--claude-code"),
149
153
  cursor: args.includes("--cursor"),
150
154
  vscode: args.includes("--vscode"),
151
155
  dryRun: args.includes("--dry-run"),
152
156
  useGlobalBinary: true,
153
- all: !args.includes("--claude-code") && !args.includes("--cursor") && !args.includes("--vscode")
157
+ all: noEditorFlag,
158
+ interactive: !args.includes("--yes") && !args.includes("--non-interactive")
154
159
  };
155
160
  await runInstall(options);
156
161
  break;
@@ -6,7 +6,9 @@
6
6
  import { readFileSync, writeFileSync, mkdirSync, existsSync, copyFileSync } from "node:fs";
7
7
  import { dirname, join, resolve } from "node:path";
8
8
  import { homedir, platform } from "node:os";
9
+ import * as https from "node:https";
9
10
  import { fileURLToPath } from "node:url";
11
+ import { runOnboarding, installSecurityTools, commandExists, SECURITY_TOOLS } from "./onboarding.js";
10
12
  const __dirname = dirname(fileURLToPath(import.meta.url));
11
13
  const PKG_ROOT = resolve(__dirname, "../..");
12
14
  function resolveHome(p) {
@@ -157,8 +159,83 @@ function installSkill(dryRun) {
157
159
  }
158
160
  process.stdout.write(` ${dryRun ? "[dry-run] would copy" : "installed"} skill: ${skillDest}\n`);
159
161
  }
162
+ /**
163
+ * Download a skill SKILL.md from a remote URL and save it to ~/.claude/skills/{skillName}/SKILL.md.
164
+ * Used for lazy on-demand skill installation — all sub-agents are downloaded this way at first use.
165
+ * Mirrors the same pattern used for security tool binary downloads in onboarding.ts.
166
+ */
167
+ // CWE-22: only alphanumeric, hyphens, and dots allowed in skill names
168
+ const SAFE_SKILL_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;
169
+ export async function downloadSkill(skillName, url, dryRun = false) {
170
+ if (!SAFE_SKILL_NAME_RE.test(skillName)) {
171
+ process.stdout.write(` [error] invalid skill name "${skillName}" — skipping download\n`);
172
+ return;
173
+ }
174
+ const skillDest = resolveHome(`~/.claude/skills/${skillName}/SKILL.md`);
175
+ if (dryRun) {
176
+ process.stdout.write(` [dry-run] would download skill "${skillName}" from ${url} → ${skillDest}\n`);
177
+ return;
178
+ }
179
+ const MAX_SKILL_BYTES = 512 * 1024; // 512 KB — skills are markdown files
180
+ const content = await new Promise((resolve) => {
181
+ const req = https.get(url, { headers: { "User-Agent": "security-mcp" } }, (res) => {
182
+ if ((res.statusCode ?? 500) >= 400) {
183
+ res.resume();
184
+ resolve(null);
185
+ return;
186
+ }
187
+ let body = "";
188
+ res.setEncoding("utf8");
189
+ res.on("data", (chunk) => {
190
+ body += chunk;
191
+ if (Buffer.byteLength(body, "utf8") > MAX_SKILL_BYTES) {
192
+ req.destroy();
193
+ resolve(null);
194
+ }
195
+ });
196
+ res.on("end", () => resolve(body));
197
+ });
198
+ req.on("error", () => resolve(null));
199
+ req.setTimeout(10000, () => { req.destroy(); resolve(null); });
200
+ });
201
+ if (!content) {
202
+ process.stdout.write(` [error] failed to download skill "${skillName}" from ${url}\n`);
203
+ return;
204
+ }
205
+ mkdirSync(dirname(skillDest), { recursive: true });
206
+ writeFileSync(skillDest, content, "utf-8");
207
+ process.stdout.write(` installed skill: ${skillDest}\n`);
208
+ }
209
+ /**
210
+ * Eagerly install the orchestrator skill (bundled in the package) plus record
211
+ * its version so orchestration.ensure_skill can detect future updates.
212
+ */
213
+ function installOrchestratorSkill(dryRun) {
214
+ const skillName = "ciso-orchestrator";
215
+ const skillSrc = join(PKG_ROOT, "skills", skillName, "SKILL.md");
216
+ const skillDest = resolveHome(`~/.claude/skills/${skillName}/SKILL.md`);
217
+ if (!existsSync(skillSrc)) {
218
+ process.stdout.write(` [skip] skills/${skillName}/SKILL.md not found in package\n`);
219
+ return;
220
+ }
221
+ if (!dryRun) {
222
+ mkdirSync(dirname(skillDest), { recursive: true });
223
+ copyFileSync(skillSrc, skillDest);
224
+ }
225
+ process.stdout.write(` ${dryRun ? "[dry-run] would copy" : "installed"} skill: ${skillDest}\n`);
226
+ }
160
227
  export async function runInstall(opts) {
161
228
  const dryRun = opts.dryRun;
229
+ // ── Interactive onboarding (skipped when --yes or non-TTY) ──────────────
230
+ if (opts.interactive && !dryRun) {
231
+ const onboarding = await runOnboarding();
232
+ if (onboarding?.installTools) {
233
+ const toInstall = SECURITY_TOOLS.filter((t) => !commandExists(t.id));
234
+ process.stdout.write("\nInstalling security scanning tools...\n");
235
+ await installSecurityTools(toInstall);
236
+ process.stdout.write("\n");
237
+ }
238
+ }
162
239
  process.stdout.write(`\nsecurity-mcp installer${dryRun ? " (dry-run)" : ""}\n`);
163
240
  process.stdout.write("=".repeat(40) + "\n\n");
164
241
  const targets = getEditorTargets(opts);
@@ -184,11 +261,12 @@ export async function runInstall(opts) {
184
261
  process.stdout.write(` [error] ${err instanceof Error ? err.message : String(err)}\n`);
185
262
  }
186
263
  }
187
- // Install Claude Code skill if Claude Code is in scope
264
+ // Install Claude Code skills if Claude Code is in scope
188
265
  const hasClaudeCode = targets.some((t) => t.name.startsWith("Claude Code"));
189
266
  if (hasClaudeCode || opts.all) {
190
- process.stdout.write("\nInstalling Claude Code skill...\n");
267
+ process.stdout.write("\nInstalling Claude Code skills...\n");
191
268
  installSkill(dryRun);
269
+ installOrchestratorSkill(dryRun);
192
270
  }
193
271
  process.stdout.write("\nInstalling security policy...\n");
194
272
  installPolicy(dryRun);