agent-security-scanner-mcp 4.1.0 → 4.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.
- package/README.md +198 -1
- package/index.js +139 -0
- package/openclaw.plugin.json +21 -1
- package/package.json +1 -1
- package/src/lib/cyclonedx.js +113 -0
- package/src/lib/lockfile-parsers.js +671 -0
- package/src/lib/osv-client.js +254 -0
- package/src/lib/purl.js +90 -0
- package/src/lib/sbom-component.js +88 -0
- package/src/tools/sbom-diff.js +199 -0
- package/src/tools/sbom-generate.js +116 -0
- package/src/tools/sbom-hallucinations.js +117 -0
- package/src/tools/sbom-report.js +271 -0
- package/src/tools/sbom-vulnerabilities.js +121 -0
package/README.md
CHANGED
|
@@ -63,6 +63,8 @@ Continue reading below for full version documentation →
|
|
|
63
63
|
|
|
64
64
|
---
|
|
65
65
|
|
|
66
|
+
> **New in v4.1.0:** SBOM generation and dependency vulnerability analysis — generates CycloneDX v1.5 SBOMs, scans against OSV.dev for CVEs, detects hallucinated packages, compares baselines, and generates HTML audit reports. Supports 8 lock file formats and 7 manifest formats across npm, Python, Go, Rust, Ruby, and Java ecosystems. [See SBOM Tools](#-sbom--supply-chain-analysis-new-in-v410).
|
|
67
|
+
>
|
|
66
68
|
> **New in v4.0.0:** LLM-powered semantic code review agent with intent profiling — understands what your project is supposed to do and flags patterns that violate that intent. Same `eval()` call = safe in a build tool, dangerous in an e-commerce app. Supports Claude CLI (no API key needed!), Anthropic, and OpenAI. [See code-review-agent](#-llm-powered-code-review-agent-new-in-v400).
|
|
67
69
|
>
|
|
68
70
|
> **New in v3.11.0:** ClawHub ecosystem security scanning — scanned all 16,532 ClawHub skills and found 46% have critical vulnerabilities. New `scan-clawhub` CLI for batch scanning, 40+ prompt injection patterns, jailbreak detection (DAN mode, dev mode), data exfiltration checks. [See ClawHub Security Dashboard](https://www.proof-layer.com/dashboard).
|
|
@@ -87,6 +89,11 @@ Continue reading below for full version documentation →
|
|
|
87
89
|
| `scan_skill` | Deep security scan of an OpenClaw skill: prompt injection, AST+taint code analysis, ClawHavoc malware signatures, supply chain, rug pull. Returns A-F grade | Before installing any OpenClaw skill |
|
|
88
90
|
| `scanner_health` | Check plugin health: engine status, daemon status, package data availability | Diagnostics and plugin status |
|
|
89
91
|
| `list_security_rules` | List available security rules and fix templates | To check rule coverage for a language |
|
|
92
|
+
| `sbom_generate` | Generate CycloneDX v1.5 SBOM for a project (8 lock file formats, 7 manifest formats) | Before releases, for compliance audits |
|
|
93
|
+
| `sbom_scan_vulnerabilities` | Cross-reference SBOM against OSV.dev for CVEs with severity filtering | After generating SBOM, for security audits |
|
|
94
|
+
| `sbom_check_hallucinations` | Verify all SBOM packages exist in official registries | Before deploying, to catch AI-invented packages |
|
|
95
|
+
| `sbom_diff` | Compare current SBOM against baseline, detect added/removed/changed packages | In CI/CD to track dependency drift |
|
|
96
|
+
| `sbom_export_report` | Generate HTML or JSON audit report from SBOM with vulnerability data | For PCI-DSS compliance, security reviews |
|
|
90
97
|
|
|
91
98
|
## Quick Start
|
|
92
99
|
|
|
@@ -243,6 +250,180 @@ npx cr-agent analyze ./path/to/project -f sarif -p claude-cli
|
|
|
243
250
|
|
|
244
251
|
---
|
|
245
252
|
|
|
253
|
+
## 📦 SBOM / Supply Chain Analysis (New in v4.1.0)
|
|
254
|
+
|
|
255
|
+
Generate Software Bill of Materials (SBOM) and analyze dependencies for vulnerabilities across your entire supply chain.
|
|
256
|
+
|
|
257
|
+
### Quick Start
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# Generate SBOM for current project
|
|
261
|
+
npx agent-security-scanner-mcp sbom-generate .
|
|
262
|
+
|
|
263
|
+
# Scan for vulnerabilities against OSV.dev
|
|
264
|
+
npx agent-security-scanner-mcp sbom-vulnerabilities .
|
|
265
|
+
|
|
266
|
+
# Check for hallucinated packages
|
|
267
|
+
npx agent-security-scanner-mcp sbom-check-hallucinations .
|
|
268
|
+
|
|
269
|
+
# Compare against baseline (CI/CD)
|
|
270
|
+
npx agent-security-scanner-mcp sbom-diff . --save-baseline # First run
|
|
271
|
+
npx agent-security-scanner-mcp sbom-diff . # Subsequent runs
|
|
272
|
+
|
|
273
|
+
# Generate HTML audit report
|
|
274
|
+
npx agent-security-scanner-mcp sbom-report . --format html
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Supported Ecosystems
|
|
278
|
+
|
|
279
|
+
| Ecosystem | Lock Files | Manifests | CLI Fallback |
|
|
280
|
+
|-----------|------------|-----------|--------------|
|
|
281
|
+
| **npm** | package-lock.json (v2/v3), yarn.lock (classic/berry), pnpm-lock.yaml | package.json | `npm ls`, `pnpm list` |
|
|
282
|
+
| **Python** | poetry.lock, Pipfile.lock | requirements.txt, pyproject.toml | — |
|
|
283
|
+
| **Go** | go.sum | go.mod | `go list` |
|
|
284
|
+
| **Rust** | Cargo.lock | — | `cargo metadata` |
|
|
285
|
+
| **Ruby** | Gemfile.lock | Gemfile | — |
|
|
286
|
+
| **Java** | — | pom.xml, build.gradle | `mvn dependency:tree` |
|
|
287
|
+
|
|
288
|
+
### SBOM Tools
|
|
289
|
+
|
|
290
|
+
#### `sbom_generate`
|
|
291
|
+
|
|
292
|
+
Generate a CycloneDX v1.5 SBOM for a project. Discovers all dependencies (direct + transitive) from lock files and manifests.
|
|
293
|
+
|
|
294
|
+
```json
|
|
295
|
+
// Input
|
|
296
|
+
{ "directory_path": "./my-project", "verbosity": "compact" }
|
|
297
|
+
|
|
298
|
+
// Output
|
|
299
|
+
{
|
|
300
|
+
"total_components": 212,
|
|
301
|
+
"direct": 20,
|
|
302
|
+
"dev": 91,
|
|
303
|
+
"ecosystems": ["npm", "pypi"],
|
|
304
|
+
"components": [
|
|
305
|
+
{ "name": "express", "version": "4.18.2", "ecosystem": "npm", "isDirect": true }
|
|
306
|
+
]
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### `sbom_scan_vulnerabilities`
|
|
311
|
+
|
|
312
|
+
Cross-reference SBOM components against OSV.dev vulnerability database. Returns CVE IDs, CVSS scores, severity, and fix recommendations.
|
|
313
|
+
|
|
314
|
+
```json
|
|
315
|
+
// Input
|
|
316
|
+
{ "directory_path": "./my-project", "severity_threshold": "medium" }
|
|
317
|
+
|
|
318
|
+
// Output
|
|
319
|
+
{
|
|
320
|
+
"total_vulnerabilities": 3,
|
|
321
|
+
"by_severity": { "critical": 1, "high": 1, "medium": 1 },
|
|
322
|
+
"vulnerabilities": [
|
|
323
|
+
{
|
|
324
|
+
"id": "GHSA-xxxx-yyyy-zzzz",
|
|
325
|
+
"package": "lodash",
|
|
326
|
+
"severity": "critical",
|
|
327
|
+
"cvss": 9.8,
|
|
328
|
+
"fixed_version": "4.17.21"
|
|
329
|
+
}
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
#### `sbom_check_hallucinations`
|
|
335
|
+
|
|
336
|
+
Check all packages in an SBOM against official registries to detect AI-invented package names.
|
|
337
|
+
|
|
338
|
+
```json
|
|
339
|
+
// Input
|
|
340
|
+
{ "directory_path": "./my-project" }
|
|
341
|
+
|
|
342
|
+
// Output
|
|
343
|
+
{
|
|
344
|
+
"total_checked": 212,
|
|
345
|
+
"hallucinated_count": 1,
|
|
346
|
+
"unsupported_ecosystems": ["go", "java"],
|
|
347
|
+
"hallucinated": [
|
|
348
|
+
{ "name": "react-async-utils-helper", "ecosystem": "npm" }
|
|
349
|
+
]
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
#### `sbom_diff`
|
|
354
|
+
|
|
355
|
+
Compare current project SBOM against a stored baseline. Detects added, removed, and version-changed packages.
|
|
356
|
+
|
|
357
|
+
```json
|
|
358
|
+
// Input (first run)
|
|
359
|
+
{ "directory_path": "./my-project", "save_baseline": true }
|
|
360
|
+
|
|
361
|
+
// Output
|
|
362
|
+
{ "message": "Baseline saved to .scanner/sbom-baseline.json" }
|
|
363
|
+
|
|
364
|
+
// Input (subsequent runs)
|
|
365
|
+
{ "directory_path": "./my-project" }
|
|
366
|
+
|
|
367
|
+
// Output
|
|
368
|
+
{
|
|
369
|
+
"added": [{ "name": "lodash", "version": "4.17.21", "ecosystem": "npm" }],
|
|
370
|
+
"removed": [],
|
|
371
|
+
"changed": [{ "name": "express", "from": "4.17.1", "to": "4.18.2" }]
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
#### `sbom_export_report`
|
|
376
|
+
|
|
377
|
+
Generate an HTML or JSON audit report from SBOM data, optionally enriched with vulnerability scan results.
|
|
378
|
+
|
|
379
|
+
```json
|
|
380
|
+
// Input
|
|
381
|
+
{
|
|
382
|
+
"directory_path": "./my-project",
|
|
383
|
+
"format": "html",
|
|
384
|
+
"include_vulnerabilities": true,
|
|
385
|
+
"output_path": "./sbom-report.html"
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Output
|
|
389
|
+
{
|
|
390
|
+
"report_path": "./sbom-report.html",
|
|
391
|
+
"components": 212,
|
|
392
|
+
"vulnerabilities": 3
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### CLI Commands
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# Generate SBOM
|
|
400
|
+
sbom-generate <dir> [--save] [--output <path>] [--verbosity minimal|compact|full]
|
|
401
|
+
|
|
402
|
+
# Scan vulnerabilities
|
|
403
|
+
sbom-vulnerabilities <dir> [--sbom-path <path>] [--verbosity minimal|compact|full]
|
|
404
|
+
|
|
405
|
+
# Check hallucinations
|
|
406
|
+
sbom-check-hallucinations <dir> [--verbosity minimal|compact|full]
|
|
407
|
+
|
|
408
|
+
# Compare baseline
|
|
409
|
+
sbom-diff <dir> [--save-baseline] [--baseline-path <path>] [--verbosity minimal|compact|full]
|
|
410
|
+
|
|
411
|
+
# Generate report
|
|
412
|
+
sbom-report <dir> [--format html|json] [--output <path>] [--no-vulnerabilities]
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Features
|
|
416
|
+
|
|
417
|
+
- **CycloneDX v1.5 JSON** — Industry-standard SBOM format
|
|
418
|
+
- **OSV.dev Integration** — Real-time vulnerability data with 24-hour local cache
|
|
419
|
+
- **Multi-Ecosystem** — Single scan discovers dependencies across all package managers
|
|
420
|
+
- **Direct vs Transitive** — Distinguishes direct dependencies from transitive ones
|
|
421
|
+
- **Dev Dependencies** — Optionally include/exclude development dependencies
|
|
422
|
+
- **Baseline Comparison** — Track dependency drift over time
|
|
423
|
+
- **HTML Reports** — Visual dashboard with severity charts for compliance audits
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
246
427
|
## Tool Reference
|
|
247
428
|
|
|
248
429
|
### `scan_security`
|
|
@@ -1158,7 +1339,7 @@ AI coding agents introduce attack surfaces that traditional security tools weren
|
|
|
1158
1339
|
|----------|-------|
|
|
1159
1340
|
| **Transport** | stdio |
|
|
1160
1341
|
| **Package** | `agent-security-scanner-mcp` (npm) |
|
|
1161
|
-
| **Tools** |
|
|
1342
|
+
| **Tools** | 17 |
|
|
1162
1343
|
| **Languages** | 12 |
|
|
1163
1344
|
| **Ecosystems** | 7 |
|
|
1164
1345
|
| **Auth** | None required |
|
|
@@ -1240,6 +1421,22 @@ All MCP tools support a `verbosity` parameter to minimize context window consump
|
|
|
1240
1421
|
|
|
1241
1422
|
## Changelog
|
|
1242
1423
|
|
|
1424
|
+
### v4.1.0 (2026-03-27) - SBOM Generation & Vulnerability Analysis
|
|
1425
|
+
|
|
1426
|
+
**🚀 New Feature: Software Bill of Materials (SBOM)**
|
|
1427
|
+
|
|
1428
|
+
- **5 New MCP Tools:** `sbom_generate`, `sbom_scan_vulnerabilities`, `sbom_check_hallucinations`, `sbom_diff`, `sbom_export_report`
|
|
1429
|
+
- **CycloneDX v1.5:** Industry-standard SBOM format output
|
|
1430
|
+
- **8 Lock File Parsers:** package-lock.json (v2/v3), yarn.lock (classic/berry), pnpm-lock.yaml, poetry.lock, Pipfile.lock, Cargo.lock, go.sum, Gemfile.lock
|
|
1431
|
+
- **7 Manifest Parsers:** package.json, requirements.txt, pyproject.toml, go.mod, Gemfile, pom.xml, build.gradle
|
|
1432
|
+
- **CLI Fallbacks:** npm ls, pnpm list, cargo metadata, go list, mvn dependency:tree
|
|
1433
|
+
- **OSV.dev Integration:** Real-time vulnerability database with 24-hour local cache
|
|
1434
|
+
- **Baseline Comparison:** Track dependency drift with save/compare workflow
|
|
1435
|
+
- **HTML Reports:** Visual dashboard with severity charts for compliance
|
|
1436
|
+
- **86 New Tests:** Comprehensive coverage across all SBOM features
|
|
1437
|
+
|
|
1438
|
+
---
|
|
1439
|
+
|
|
1243
1440
|
### v4.0.0 (2026-03-21) - LLM-Powered Code Review Agent
|
|
1244
1441
|
|
|
1245
1442
|
**🚀 Major Release: LLM-Powered Semantic Code Review**
|
package/index.js
CHANGED
|
@@ -28,6 +28,11 @@ import { runInitHooks } from './src/cli/init-hooks.js';
|
|
|
28
28
|
import { runReport } from './src/cli/report.js';
|
|
29
29
|
import { scoreAivssSchema, scoreAivssTool } from './src/tools/score-aivss.js';
|
|
30
30
|
import { complianceControlsSchema, getComplianceControls } from './src/tools/compliance-controls.js';
|
|
31
|
+
import { sbomGenerateSchema, sbomGenerate } from './src/tools/sbom-generate.js';
|
|
32
|
+
import { sbomVulnerabilitiesSchema, sbomScanVulnerabilities } from './src/tools/sbom-vulnerabilities.js';
|
|
33
|
+
import { sbomHallucinationsSchema, sbomCheckHallucinations } from './src/tools/sbom-hallucinations.js';
|
|
34
|
+
import { sbomDiffSchema, sbomDiff } from './src/tools/sbom-diff.js';
|
|
35
|
+
import { sbomReportSchema, sbomExportReport } from './src/tools/sbom-report.js';
|
|
31
36
|
|
|
32
37
|
// Handle both ESM and CJS bundling (Smithery bundles to CJS)
|
|
33
38
|
let __dirname;
|
|
@@ -252,6 +257,45 @@ server.tool(
|
|
|
252
257
|
getComplianceControls
|
|
253
258
|
);
|
|
254
259
|
|
|
260
|
+
// ===========================================
|
|
261
|
+
// SBOM / SUPPLY CHAIN ANALYSIS
|
|
262
|
+
// ===========================================
|
|
263
|
+
|
|
264
|
+
server.tool(
|
|
265
|
+
"sbom_generate",
|
|
266
|
+
"Generate a CycloneDX v1.5 SBOM for a project. Discovers all dependencies (direct + transitive) from lock files and manifests across Node.js, Python, Go, Rust, Ruby, Java. Use verbosity='minimal' for counts, 'compact' (default) for component list, 'full' for complete CycloneDX JSON.",
|
|
267
|
+
sbomGenerateSchema,
|
|
268
|
+
sbomGenerate
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
server.tool(
|
|
272
|
+
"sbom_scan_vulnerabilities",
|
|
273
|
+
"Cross-reference SBOM components against OSV.dev vulnerability database. Returns CVE IDs, CVSS scores, severity, and fix recommendations. Accepts directory_path (generates fresh) or sbom_path (loads saved artifact).",
|
|
274
|
+
sbomVulnerabilitiesSchema,
|
|
275
|
+
sbomScanVulnerabilities
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
server.tool(
|
|
279
|
+
"sbom_check_hallucinations",
|
|
280
|
+
"Check all packages in an SBOM against official registries to detect hallucinated (AI-invented) package names. Supports npm, pypi, rubygems, dart, perl, raku, crates. Go/Java marked as unsupported.",
|
|
281
|
+
sbomHallucinationsSchema,
|
|
282
|
+
sbomCheckHallucinations
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
server.tool(
|
|
286
|
+
"sbom_diff",
|
|
287
|
+
"Compare current project SBOM against a stored baseline. Reports added, removed, and version-changed packages. Use save_baseline=true to create initial baseline.",
|
|
288
|
+
sbomDiffSchema,
|
|
289
|
+
sbomDiff
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
server.tool(
|
|
293
|
+
"sbom_export_report",
|
|
294
|
+
"Generate an HTML or JSON audit report from SBOM data, optionally enriched with vulnerability scan results. Suitable for PCI-DSS and compliance audits.",
|
|
295
|
+
sbomReportSchema,
|
|
296
|
+
sbomExportReport
|
|
297
|
+
);
|
|
298
|
+
|
|
255
299
|
// ===========================================
|
|
256
300
|
// CLI COMMANDS - Extracted to src/cli/
|
|
257
301
|
// ===========================================
|
|
@@ -524,6 +568,95 @@ const cliArgs = process.argv.slice(2);
|
|
|
524
568
|
console.error(` Error: ${err.message}\n`);
|
|
525
569
|
process.exit(1);
|
|
526
570
|
});
|
|
571
|
+
} else if (cliArgs[0] === 'sbom-generate') {
|
|
572
|
+
const dirPath = cliArgs[1] || '.';
|
|
573
|
+
const verbosityIdx = cliArgs.indexOf('--verbosity');
|
|
574
|
+
const verbosity = verbosityIdx !== -1 ? cliArgs[verbosityIdx + 1] : 'compact';
|
|
575
|
+
const save = cliArgs.includes('--save');
|
|
576
|
+
const outIdx = cliArgs.indexOf('--output');
|
|
577
|
+
const outputPath = outIdx !== -1 ? cliArgs[outIdx + 1] : (save ? join(dirPath, '.scanner', 'sbom.json') : undefined);
|
|
578
|
+
|
|
579
|
+
sbomGenerate({ directory_path: dirPath, output_path: outputPath, verbosity }).then(result => {
|
|
580
|
+
const output = JSON.parse(result.content[0].text);
|
|
581
|
+
console.log(JSON.stringify(output, null, 2));
|
|
582
|
+
process.exit(0);
|
|
583
|
+
}).catch(err => {
|
|
584
|
+
console.error(JSON.stringify({ error: err.message }));
|
|
585
|
+
process.exit(1);
|
|
586
|
+
});
|
|
587
|
+
} else if (cliArgs[0] === 'sbom-vulnerabilities') {
|
|
588
|
+
const dirPath = cliArgs[1] || '.';
|
|
589
|
+
const verbosityIdx = cliArgs.indexOf('--verbosity');
|
|
590
|
+
const verbosity = verbosityIdx !== -1 ? cliArgs[verbosityIdx + 1] : 'compact';
|
|
591
|
+
const sbomIdx = cliArgs.indexOf('--sbom-path');
|
|
592
|
+
const sbomPath = sbomIdx !== -1 ? cliArgs[sbomIdx + 1] : undefined;
|
|
593
|
+
|
|
594
|
+
sbomScanVulnerabilities({
|
|
595
|
+
directory_path: sbomPath ? undefined : dirPath,
|
|
596
|
+
sbom_path: sbomPath,
|
|
597
|
+
verbosity,
|
|
598
|
+
}).then(result => {
|
|
599
|
+
const output = JSON.parse(result.content[0].text);
|
|
600
|
+
console.log(JSON.stringify(output, null, 2));
|
|
601
|
+
process.exit(output.total_vulnerabilities > 0 ? 1 : 0);
|
|
602
|
+
}).catch(err => {
|
|
603
|
+
console.error(JSON.stringify({ error: err.message }));
|
|
604
|
+
process.exit(1);
|
|
605
|
+
});
|
|
606
|
+
} else if (cliArgs[0] === 'sbom-check-hallucinations') {
|
|
607
|
+
const dirPath = cliArgs[1] || '.';
|
|
608
|
+
const verbosityIdx = cliArgs.indexOf('--verbosity');
|
|
609
|
+
const verbosity = verbosityIdx !== -1 ? cliArgs[verbosityIdx + 1] : 'compact';
|
|
610
|
+
|
|
611
|
+
loadPackageLists();
|
|
612
|
+
sbomCheckHallucinations({ directory_path: dirPath, verbosity }).then(result => {
|
|
613
|
+
const output = JSON.parse(result.content[0].text);
|
|
614
|
+
console.log(JSON.stringify(output, null, 2));
|
|
615
|
+
process.exit(output.hallucinated_count > 0 ? 1 : 0);
|
|
616
|
+
}).catch(err => {
|
|
617
|
+
console.error(JSON.stringify({ error: err.message }));
|
|
618
|
+
process.exit(1);
|
|
619
|
+
});
|
|
620
|
+
} else if (cliArgs[0] === 'sbom-diff') {
|
|
621
|
+
const dirPath = cliArgs[1] || '.';
|
|
622
|
+
const verbosityIdx = cliArgs.indexOf('--verbosity');
|
|
623
|
+
const verbosity = verbosityIdx !== -1 ? cliArgs[verbosityIdx + 1] : 'compact';
|
|
624
|
+
const saveBaseline = cliArgs.includes('--save-baseline');
|
|
625
|
+
const baselineIdx = cliArgs.indexOf('--baseline-path');
|
|
626
|
+
const baselinePath = baselineIdx !== -1 ? cliArgs[baselineIdx + 1] : undefined;
|
|
627
|
+
|
|
628
|
+
sbomDiff({ directory_path: dirPath, baseline_path: baselinePath, save_baseline: saveBaseline, verbosity }).then(result => {
|
|
629
|
+
const output = JSON.parse(result.content[0].text);
|
|
630
|
+
console.log(JSON.stringify(output, null, 2));
|
|
631
|
+
process.exit(0);
|
|
632
|
+
}).catch(err => {
|
|
633
|
+
console.error(JSON.stringify({ error: err.message }));
|
|
634
|
+
process.exit(1);
|
|
635
|
+
});
|
|
636
|
+
} else if (cliArgs[0] === 'sbom-report') {
|
|
637
|
+
const dirPath = cliArgs[1] || '.';
|
|
638
|
+
const verbosityIdx = cliArgs.indexOf('--verbosity');
|
|
639
|
+
const verbosity = verbosityIdx !== -1 ? cliArgs[verbosityIdx + 1] : 'compact';
|
|
640
|
+
const formatIdx = cliArgs.indexOf('--format');
|
|
641
|
+
const format = formatIdx !== -1 ? cliArgs[formatIdx + 1] : 'html';
|
|
642
|
+
const outIdx = cliArgs.indexOf('--output');
|
|
643
|
+
const outputPath = outIdx !== -1 ? cliArgs[outIdx + 1] : join(dirPath, '.scanner', 'sbom-report.html');
|
|
644
|
+
const noVulns = cliArgs.includes('--no-vulnerabilities');
|
|
645
|
+
|
|
646
|
+
sbomExportReport({
|
|
647
|
+
directory_path: dirPath,
|
|
648
|
+
format,
|
|
649
|
+
include_vulnerabilities: !noVulns,
|
|
650
|
+
output_path: outputPath,
|
|
651
|
+
verbosity,
|
|
652
|
+
}).then(result => {
|
|
653
|
+
const output = JSON.parse(result.content[0].text);
|
|
654
|
+
console.log(JSON.stringify(output, null, 2));
|
|
655
|
+
process.exit(0);
|
|
656
|
+
}).catch(err => {
|
|
657
|
+
console.error(JSON.stringify({ error: err.message }));
|
|
658
|
+
process.exit(1);
|
|
659
|
+
});
|
|
527
660
|
} else if (cliArgs[0] === 'scan-clawhub') {
|
|
528
661
|
// Import and run SAFE ClawHub scanner (no code execution)
|
|
529
662
|
await import('./src/cli/scan-clawhub-safe.js');
|
|
@@ -550,6 +683,12 @@ const cliArgs = process.argv.slice(2);
|
|
|
550
683
|
console.log(' scan-action <t> <v> Check agent action before execution');
|
|
551
684
|
console.log(' audit [--config-path] Audit OpenClaw config for security issues [experimental]');
|
|
552
685
|
console.log(' harden [--fix] Auto-harden OpenClaw configuration [experimental]\n');
|
|
686
|
+
console.log(' SBOM / Supply Chain:');
|
|
687
|
+
console.log(' sbom-generate <dir> Generate CycloneDX SBOM [--save] [--output <path>]');
|
|
688
|
+
console.log(' sbom-vulnerabilities <dir> Scan SBOM against OSV.dev [--sbom-path <path>]');
|
|
689
|
+
console.log(' sbom-check-hallucinations <dir> Check SBOM packages against registries');
|
|
690
|
+
console.log(' sbom-diff <dir> Compare SBOM against baseline [--save-baseline]');
|
|
691
|
+
console.log(' sbom-report <dir> Generate SBOM audit report [--format html|json]\n');
|
|
553
692
|
console.log(' (no args) Start MCP server on stdio\n');
|
|
554
693
|
console.log(' Options:');
|
|
555
694
|
console.log(' --verbosity <level> minimal|compact|full (default: compact)');
|
package/openclaw.plugin.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"openclaw": {
|
|
8
8
|
"extensions": ["tools", "skills"],
|
|
9
9
|
"emoji": "shield",
|
|
10
|
-
"permissions": ["fs:read"]
|
|
10
|
+
"permissions": ["fs:read", "fs:write"]
|
|
11
11
|
},
|
|
12
12
|
"tools": [
|
|
13
13
|
{
|
|
@@ -33,6 +33,26 @@
|
|
|
33
33
|
{
|
|
34
34
|
"name": "scanner_health",
|
|
35
35
|
"description": "Check plugin health status"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "sbom_generate",
|
|
39
|
+
"description": "Generate CycloneDX SBOM for a project"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "sbom_scan_vulnerabilities",
|
|
43
|
+
"description": "Scan SBOM against OSV.dev vulnerability database"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "sbom_check_hallucinations",
|
|
47
|
+
"description": "Check SBOM packages against official registries"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "sbom_diff",
|
|
51
|
+
"description": "Compare current SBOM against stored baseline"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "sbom_export_report",
|
|
55
|
+
"description": "Generate HTML/JSON SBOM audit report"
|
|
36
56
|
}
|
|
37
57
|
],
|
|
38
58
|
"skills": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-security-scanner-mcp",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.1",
|
|
4
4
|
"mcpName": "io.github.sinewaveai/agent-security-scanner-mcp",
|
|
5
5
|
"description": "Security scanner MCP server for AI coding agents. Prompt injection firewall, package hallucination detection (4.3M+ packages), 1700+ vulnerability rules with AST & taint analysis, LLM-powered semantic code review, auto-fix. For Claude Code, Cursor, Windsurf, Cline, OpenClaw.",
|
|
6
6
|
"main": "index.js",
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// CycloneDX v1.5 JSON serializer.
|
|
2
|
+
// Consumes the normalized ComponentList model from sbom-component.js.
|
|
3
|
+
|
|
4
|
+
import { randomUUID } from 'crypto';
|
|
5
|
+
|
|
6
|
+
const SPEC_VERSION = '1.5';
|
|
7
|
+
const TOOL_NAME = 'agent-security-scanner-mcp';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Serialize a ComponentList into a CycloneDX v1.5 BOM.
|
|
11
|
+
* @param {import('./sbom-component.js').ComponentList} componentList
|
|
12
|
+
* @param {object[]} [vulnerabilities=[]]
|
|
13
|
+
* @param {{ toolVersion?: string }} [options={}]
|
|
14
|
+
* @returns {object} CycloneDX JSON object
|
|
15
|
+
*/
|
|
16
|
+
export function serialize(componentList, vulnerabilities = [], options = {}) {
|
|
17
|
+
const { toolVersion = '0.0.0' } = options;
|
|
18
|
+
const { components, edges, metadata } = componentList;
|
|
19
|
+
|
|
20
|
+
const bom = {
|
|
21
|
+
bomFormat: 'CycloneDX',
|
|
22
|
+
specVersion: SPEC_VERSION,
|
|
23
|
+
serialNumber: `urn:uuid:${randomUUID()}`,
|
|
24
|
+
version: 1,
|
|
25
|
+
metadata: {
|
|
26
|
+
timestamp: new Date().toISOString(),
|
|
27
|
+
tools: [{
|
|
28
|
+
name: TOOL_NAME,
|
|
29
|
+
version: toolVersion,
|
|
30
|
+
}],
|
|
31
|
+
component: {
|
|
32
|
+
type: 'application',
|
|
33
|
+
name: metadata.name || 'unknown',
|
|
34
|
+
version: metadata.version || '0.0.0',
|
|
35
|
+
'bom-ref': `pkg:npm/${metadata.name}@${metadata.version}`,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
components: components.map(c => serializeComponent(c)),
|
|
39
|
+
dependencies: serializeDependencies(edges, components),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
if (vulnerabilities.length > 0) {
|
|
43
|
+
bom.vulnerabilities = vulnerabilities;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return bom;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function serializeComponent(component) {
|
|
50
|
+
const result = {
|
|
51
|
+
type: 'library',
|
|
52
|
+
name: component.name,
|
|
53
|
+
version: component.version,
|
|
54
|
+
purl: component.purl,
|
|
55
|
+
'bom-ref': component.purl,
|
|
56
|
+
scope: component.scope === 'optional' ? 'optional' : 'required',
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
if (component.namespace) {
|
|
60
|
+
result.group = component.namespace;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const properties = [];
|
|
64
|
+
if (component.isDev) {
|
|
65
|
+
properties.push({ name: 'cdx:development', value: 'true' });
|
|
66
|
+
}
|
|
67
|
+
if (component.ecosystem) {
|
|
68
|
+
properties.push({ name: 'cdx:ecosystem', value: component.ecosystem });
|
|
69
|
+
}
|
|
70
|
+
if (properties.length > 0) {
|
|
71
|
+
result.properties = properties;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function serializeDependencies(edges, components) {
|
|
78
|
+
if (!edges || edges.length === 0) {
|
|
79
|
+
// Return flat list — each component depends on nothing
|
|
80
|
+
return components.map(c => ({ ref: c.purl, dependsOn: [] }));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Group edges by source
|
|
84
|
+
const depMap = new Map();
|
|
85
|
+
for (const edge of edges) {
|
|
86
|
+
if (!depMap.has(edge.from)) depMap.set(edge.from, []);
|
|
87
|
+
depMap.get(edge.from).push(edge.to);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Include all components as refs, merge edges
|
|
91
|
+
const allRefs = new Set(components.map(c => c.purl));
|
|
92
|
+
for (const [from, tos] of depMap) {
|
|
93
|
+
allRefs.add(from);
|
|
94
|
+
for (const to of tos) allRefs.add(to);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return [...allRefs].map(ref => ({
|
|
98
|
+
ref,
|
|
99
|
+
dependsOn: depMap.get(ref) || [],
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Add vulnerability entries to an existing BOM.
|
|
105
|
+
* @param {object} bom - CycloneDX BOM object
|
|
106
|
+
* @param {object[]} vulnerabilities - Array of CycloneDX vulnerability objects
|
|
107
|
+
* @returns {object} The mutated BOM
|
|
108
|
+
*/
|
|
109
|
+
export function addVulnerabilities(bom, vulnerabilities) {
|
|
110
|
+
if (!bom.vulnerabilities) bom.vulnerabilities = [];
|
|
111
|
+
bom.vulnerabilities.push(...vulnerabilities);
|
|
112
|
+
return bom;
|
|
113
|
+
}
|