xploitscan 1.0.19 → 1.0.20
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/dist/index.js +112 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1262,7 +1262,7 @@ function calculateGrade(findings, _totalFiles) {
|
|
|
1262
1262
|
else if (medium >= 1) grade = capGrade("A");
|
|
1263
1263
|
let summary;
|
|
1264
1264
|
if (critical > 0) {
|
|
1265
|
-
summary = `${critical} critical ${critical === 1 ? "vulnerability" : "vulnerabilities"}
|
|
1265
|
+
summary = `${critical} critical ${critical === 1 ? "vulnerability requires" : "vulnerabilities require"} immediate attention.`;
|
|
1266
1266
|
} else if (high >= 3) {
|
|
1267
1267
|
summary = `${high} high-severity issues require urgent attention.`;
|
|
1268
1268
|
} else if (high > 0) {
|
|
@@ -3472,6 +3472,102 @@ Suggested fix: ${f.fix}` : `${f.title}: ${f.description}`;
|
|
|
3472
3472
|
console.log(JSON.stringify(sarif, null, 2));
|
|
3473
3473
|
}
|
|
3474
3474
|
|
|
3475
|
+
// src/reporters/siem.ts
|
|
3476
|
+
var ECS_SEVERITY = {
|
|
3477
|
+
// Elastic Common Schema uses 0–100 integer severity.
|
|
3478
|
+
critical: 90,
|
|
3479
|
+
high: 70,
|
|
3480
|
+
medium: 50,
|
|
3481
|
+
low: 30
|
|
3482
|
+
};
|
|
3483
|
+
var DATADOG_STATUS = {
|
|
3484
|
+
// Datadog Logs status field accepts emergency/alert/critical/error/warning/notice/info/debug.
|
|
3485
|
+
critical: "critical",
|
|
3486
|
+
high: "error",
|
|
3487
|
+
medium: "warning",
|
|
3488
|
+
low: "info"
|
|
3489
|
+
};
|
|
3490
|
+
function commonFields(result, finding) {
|
|
3491
|
+
return {
|
|
3492
|
+
rule: finding.rule,
|
|
3493
|
+
title: finding.title,
|
|
3494
|
+
description: finding.description,
|
|
3495
|
+
severity: finding.severity,
|
|
3496
|
+
file: finding.file,
|
|
3497
|
+
line: finding.line,
|
|
3498
|
+
category: finding.category,
|
|
3499
|
+
cwe: finding.cwe ?? null,
|
|
3500
|
+
owasp: finding.owasp ?? null,
|
|
3501
|
+
fix: finding.fix ?? null,
|
|
3502
|
+
scan_timestamp: result.timestamp,
|
|
3503
|
+
scan_directory: result.directory,
|
|
3504
|
+
files_scanned: result.filesScanned,
|
|
3505
|
+
scan_duration_ms: result.duration
|
|
3506
|
+
};
|
|
3507
|
+
}
|
|
3508
|
+
function renderSplunkReport(result) {
|
|
3509
|
+
for (const finding of result.findings) {
|
|
3510
|
+
const event = {
|
|
3511
|
+
time: Math.floor(new Date(result.timestamp).getTime() / 1e3),
|
|
3512
|
+
sourcetype: "xploitscan:finding",
|
|
3513
|
+
source: "xploitscan",
|
|
3514
|
+
event: commonFields(result, finding)
|
|
3515
|
+
};
|
|
3516
|
+
console.log(JSON.stringify(event));
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
function renderElasticReport(result) {
|
|
3520
|
+
for (const finding of result.findings) {
|
|
3521
|
+
const event = {
|
|
3522
|
+
"@timestamp": result.timestamp,
|
|
3523
|
+
ecs: { version: "8.11.0" },
|
|
3524
|
+
event: {
|
|
3525
|
+
kind: "alert",
|
|
3526
|
+
category: ["vulnerability"],
|
|
3527
|
+
type: ["info"],
|
|
3528
|
+
dataset: "xploitscan.finding",
|
|
3529
|
+
module: "xploitscan",
|
|
3530
|
+
severity: ECS_SEVERITY[finding.severity] ?? 50,
|
|
3531
|
+
action: finding.rule
|
|
3532
|
+
},
|
|
3533
|
+
vulnerability: {
|
|
3534
|
+
id: finding.rule,
|
|
3535
|
+
category: [finding.category],
|
|
3536
|
+
description: finding.description,
|
|
3537
|
+
severity: finding.severity,
|
|
3538
|
+
classification: finding.owasp ?? "",
|
|
3539
|
+
reference: finding.cwe ? `https://cwe.mitre.org/data/definitions/${finding.cwe.replace(/[^\d]/g, "")}.html` : ""
|
|
3540
|
+
},
|
|
3541
|
+
file: { path: finding.file },
|
|
3542
|
+
log: { level: finding.severity },
|
|
3543
|
+
message: `${finding.rule}: ${finding.title}`,
|
|
3544
|
+
xploitscan: commonFields(result, finding)
|
|
3545
|
+
};
|
|
3546
|
+
console.log(JSON.stringify(event));
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
function renderDatadogReport(result) {
|
|
3550
|
+
for (const finding of result.findings) {
|
|
3551
|
+
const event = {
|
|
3552
|
+
ddsource: "xploitscan",
|
|
3553
|
+
ddtags: [
|
|
3554
|
+
`severity:${finding.severity}`,
|
|
3555
|
+
`rule:${finding.rule}`,
|
|
3556
|
+
`category:${finding.category.toLowerCase().replace(/\s+/g, "_")}`,
|
|
3557
|
+
finding.owasp ? `owasp:${finding.owasp.replace(/\s+/g, "_")}` : "",
|
|
3558
|
+
finding.cwe ? `cwe:${finding.cwe}` : ""
|
|
3559
|
+
].filter(Boolean).join(","),
|
|
3560
|
+
service: "xploitscan",
|
|
3561
|
+
hostname: "xploitscan-cli",
|
|
3562
|
+
status: DATADOG_STATUS[finding.severity] ?? "info",
|
|
3563
|
+
message: `${finding.rule}: ${finding.title} \u2014 ${finding.description}`,
|
|
3564
|
+
timestamp: result.timestamp,
|
|
3565
|
+
xploitscan: commonFields(result, finding)
|
|
3566
|
+
};
|
|
3567
|
+
console.log(JSON.stringify(event));
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
|
|
3475
3571
|
// src/commands/scan.ts
|
|
3476
3572
|
async function scanCommand(directory, options) {
|
|
3477
3573
|
const dir = resolve2(directory || ".");
|
|
@@ -3738,6 +3834,15 @@ async function scanCommand(directory, options) {
|
|
|
3738
3834
|
case "sarif":
|
|
3739
3835
|
renderSarifReport(result);
|
|
3740
3836
|
break;
|
|
3837
|
+
case "splunk-hec":
|
|
3838
|
+
renderSplunkReport(result);
|
|
3839
|
+
break;
|
|
3840
|
+
case "elastic-ecs":
|
|
3841
|
+
renderElasticReport(result);
|
|
3842
|
+
break;
|
|
3843
|
+
case "datadog-logs":
|
|
3844
|
+
renderDatadogReport(result);
|
|
3845
|
+
break;
|
|
3741
3846
|
default:
|
|
3742
3847
|
renderTerminalReport(result, fileContentsForAnalysis);
|
|
3743
3848
|
break;
|
|
@@ -4143,8 +4248,12 @@ async function cursorInstallCommand(opts = {}) {
|
|
|
4143
4248
|
var program = new Command();
|
|
4144
4249
|
program.name("xploitscan").description(
|
|
4145
4250
|
"AI security scanner for vibe-coded apps. Find vulnerabilities before attackers do."
|
|
4146
|
-
).version("1.0.
|
|
4147
|
-
program.command("scan").description("Scan a directory for security vulnerabilities").argument("[directory]", "Directory to scan", ".").option("--no-ai", "Skip AI-powered analysis").option(
|
|
4251
|
+
).version("1.0.20");
|
|
4252
|
+
program.command("scan").description("Scan a directory for security vulnerabilities").argument("[directory]", "Directory to scan", ".").option("--no-ai", "Skip AI-powered analysis").option(
|
|
4253
|
+
"-f, --format <format>",
|
|
4254
|
+
"Output format: terminal, json, sarif, splunk-hec, elastic-ecs, datadog-logs",
|
|
4255
|
+
"terminal"
|
|
4256
|
+
).option("-v, --verbose", "Show detailed output", false).option("--diff [base]", "Scan only files changed vs base branch (default: main)").option("-w, --watch", "Watch for file changes and re-scan automatically", false).action(async (directory, opts) => {
|
|
4148
4257
|
await scanCommand(directory, {
|
|
4149
4258
|
directory,
|
|
4150
4259
|
aiAnalysis: opts.ai,
|